带通配符的 Logback 记录器名称

Logback logger name with wildcard

是否可以对匹配不同包的记录器名称使用通配符,这样我们就不必单独指定它们了?所以而不是写

<logger name="com.package1.web" level="debug"   
<logger name="com.package2.web" level="debug"  
<logger name="com.package3.web" level="debug"  

我只想指定一个条目,有点像这样:

<logger name="com.*.web" level="debug"  

如果有人知道一种方法或者只是它不可能,我将非常感激

TL;DR

Logback 不支持记录器名称中中间级别的通配符。

详情

Logback(隐式)支持通配符 在记录器名称的末尾 ,因此 <logger name="com.package1.web" ...> 实际上意味着:

  • 类 in com.package1.web and in any sub packages of com.package1.web

Logback 通过创建记录器的层次结构来做到这一点; com.package1.web 的记录器由 com.package1 的记录器作为父项,com 的记录器作为 ROOT 记录器的父项。

因此,如果您声明 <logger name="com.package1.web" level="debug"> 然后尝试为 com.package1.web.foo.bar 上的记录器发出调试日志消息,Logback 将沿着该记录器的层次结构向上移动,直到它找到 DEBUG 级别已启用,它会在 com.package1.web 找到它,因此它会发出 DEBUG 日志事件。

但是,Logback 不会在记录器名称的中间级别创建基于通配符的层次结构。所以,这个...

<logger name="com.*.web" level="debug">

... 不会导致 Logback 创建记录器:

  • com.package1.web
  • com.package2.web
  • com.package3.web

当通配符出现在记录器名称的中间级别时,将不会应用 Logback 的层次结构行为。

可能的解决方案

此层次结构行为的一个好处是它允许您将记录器配置应用到包和该包下的所有 class,即它在两者之间创建 关联 记录器实例基于他们的出身。您 可以 通过提供一个明确的记录器名称来建立这种关联,而不是将其默认为当前的 class 名称。

例如:

<logger name="DEBUG_LOGGER" level="debug">

然后你想在任何地方使用调试记录器只需创建一个 Logger 实例,如下所示:

private final Logger logger = LoggerFactory.getLogger("DEBUG_LOGGER");

显然,这种方法也有缺点,我在这里提到它只是为了表明还有另一种方法(除了完全限定的 class 名称)来关联记录器实例并将级别应用于他们。

您可以使用 appender 中的过滤器来做到这一点。基本上你必须为com.*设置一个DEBUG级别的记录器,并应用一个过滤器拒绝所有DEBUG(或更低)事件不是 com.*.web.

我承认很绕口

在性能方面它也很差:DEBUG 事件是为 所有 com.* 事件创建的,并且仅在附加程序中它们被丢弃或保留。

无论如何,示例 logback.xml 文件:

<configuration scan="true" debug="true">
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
            <evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator">
                <expression>
                    !(e.loggerName ==~ "com\..*\.web") &amp;&amp;
                    DEBUG.toInt() >= e.level.toInt()
                </expression>
            </evaluator>
            <OnMismatch>NEUTRAL</OnMismatch>
            <OnMatch>DENY</OnMatch>
        </filter>
        <encoder>
            <pattern>%p [%d{HH:mm:ss,SSS}] %c - %m\n</pattern>
        </encoder>
    </appender>

    <logger name="com" level="DEBUG" />

    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

测试代码:

public void test() throws Exception{
    getLogger("com.package1.web").debug("some debug onto com.package1.web");
    getLogger("com.package2.web").debug("some debug onto com.package2.web");
    getLogger("com.package3.web").debug("some debug onto com.package3.web");
    getLogger("com.package1.web").info("some info onto com.package1.web");
    getLogger("com.package2.web").info("some info onto com.package2.web");
    getLogger("com.package3.web").info("some info onto com.package3.web");
    getLogger("com.package3.notweb").debug("some debug onto com.package3.notweb");
    getLogger("com.package3.notweb").info("some info onto com.package3.notweb");
}

public Logger getLogger(String loggerName) {
    return LoggerFactory.getLogger(loggerName);
}

结果:

DEBUG [12:30:46] com.package1.web - some debug onto com.package1.web
DEBUG [12:30:46] com.package2.web - some debug onto com.package2.web
DEBUG [12:30:46] com.package3.web - some debug onto com.package3.web
INFO [12:30:46] com.package1.web - some info onto com.package1.web
INFO [12:30:46] com.package2.web - some info onto com.package2.web
INFO [12:30:46] com.package3.web - some info onto com.package3.web
INFO [12:30:46] com.package3.notweb - some info onto com.package3.notweb

如您所见,DEBUG 日志仅针对 com.*.web.

写入