javalogbackslf4jlomboklogback-classic

Custom Logback Appender not activated


Java 11 and logback-classic-1.2.11 here. I'm trying to write my own custom appender and am following this Baeldung article to test it out.

My src/main/java/myapp/logging/CatAppender appender (on the runtime classpath):

public class CatAppender extends AppenderBase<ILoggingEvent> {
    @Override
    protected void append(ILoggingEvent eventObject) {
        System.out.println("meow");
    }
}

My src/main/resources/logback.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">

    <appender name="cat" class="myapp.logging.CatAppender"/>

    <root level="info">
        <appender-ref ref="cat" />
    </root>

</configuration>

In my build.gradle I specify to use logback and Lombok:

plugins {
    id "io.freefair.lombok" version '6.4.0'
}

dependencies {
    implementation (
        'ch.qos.logback:logback-classic:1.2.11'
        ,'org.projectlombok:lombok:1.18.16'
    )
}

And then in my Java code I use Lombok to inject an SLF4J logger like so:

@Slf4j
public class SomethingDoer {

    public void doSomething() {
        log.info("this should invoke the CatAppender...");
    }

}

But when SomethingDoer#doSomething() runs, I don't see a meow printed to my STDOUT console. Have I wired anything up incorrectly here?


Solution

  • One major miss in that Baeldung article is the fact that you need to call the custom appender's start() method, otherwise log messages will not be logged by the AppenderBase subclass.

    In my case I just call start() from inside the CatAppender constructor and everything works:

    public class CatAppender extends AppenderBase<ILoggingEvent> {
        public CatAppender() {
            super();
            start();
        }
    
        @Override
        protected void append(ILoggingEvent eventObject) {
            System.out.println("meow");
        }
    }
    

    FWIW the start() is considered an initialization or constructor-level check. You should make sure everything inside your appender subclass is "healthy" enough to begin logging, and only then, call start().

    So in the case of my CatAppender since its just "meowing" to STDOUT I can do that from inside the constructor. Other, more complicated subclasses will have to figure out when/where its appropriate to activate the appender via start().