Logback logger name with wildcard

You can do that with Filters in the appender. Basically you have to set up a logger for com.* with DEBUG level, and apply a filter which DENIES all DEBUG (or lower) events which are NOT com.*.web.

I admit that it is quite convoluted.

Performance-wise it is also poor: DEBUG events are created for all com.* events, and only at the appender they are thrown away or kept.

Anyway, example logback.xml file:

<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>

Test code:

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);
}

Result:

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

as you can see, DEBUG logs are written only for com.*.web.


TL;DR

Logback does not support wildcards at intermediate levels in the logger name.

Detail

Logback (implicitly) supports wildcards at the end of the logger name, so <logger name="com.package1.web" ...> effectively means:

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

Logback does this by creating a hierarchy of loggers; the logger for com.package1.web is parented by a logger for com.package1 which is parented by a logger for com which is parent by the ROOT logger.

So, if you declare <logger name="com.package1.web" level="debug"> and then attempt to emit a debug log message for a logger on com.package1.web.foo.bar Logback will walk up that logger's hierarchy until it finds a logger for which the DEBUG level is enabled, it will find this at com.package1.web and hence it will emit the DEBUG log event.

However, Logback will not create a hierarchy based on a wilcard at an intermediate level in the logger name. So, this ...

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

... will not cause Logback to create loggers for:

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

Logback's hierarchy behaviour will not be applied when the wildcard is presented at an intermediate level in the logger name.

Possible Solution

One benefit of this hierarchy behaviour is that it allows you to apply logger configuration to a package and all classes below that package i.e. it creates an association between logger instances based on their parentage. You could make this association by providing an explicit logger name, rather than defaulting it to the current class name.

For example:

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

Then everywhere you want to use the debug logger just create a Logger instance like so:

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

Clearly, there are drawback to this approach too, I'm just mentioning it here to show that there is another way (other than fully qualified class name) to associate logger instances and apply a level to them.