Skip to content

log4j custom appender stop method not getting called

I am trying to implement a custom log appender for log4j and will need to initialize some resources before start and cleanup at the end. Somehow my stop method will not be executed. I’ve tried using LogManager.shutdown(); but I cannot see my method getting called.

This is my appender class:

@Plugin(name = "CELogAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
public class CELogAppender extends AbstractAppender {
    private final ConcurrentMap<String, LogEvent> eventMap = new ConcurrentHashMap<>();

    protected CELogAppender(String name, Filter filter, Layout<? extends Serializable> layout,
                            boolean ignoreExceptions, Property[] properties) {
        super(name, filter, layout, ignoreExceptions, properties);
        System.out.println("new celogappender");
    }

    public static CELogAppender createAppender(@PluginAttribute("name") String name,
                                               @PluginAttribute("Filter") Filter filter,
                                               @PluginAttribute("Layout") Layout<? extends Serializable> layout) {
        return new CELogAppender(name, filter, layout, false, null);
    }

    @Override
    public void append(LogEvent event) {
        eventMap.put(Instant.now().toString(), event);
        System.out.println("event added");
    }

    public ConcurrentMap<String, LogEvent> getEvents() {
        return eventMap;
    }

    @Override
    public void start() {
        super.start();
        System.out.println("start appender");
    }

    @Override
    public void stop() {
        super.stop();
        System.out.println("stop appender");
    }
}

And this is a simple test

public class CELogAppenderTests {
    private static Logger logger;
    private static CELogAppender ceLogAppender;

    @BeforeAll
    public static void setup() {
        logger = LogManager.getLogger(CELogAppenderTests.class.getName());
        LoggerContext loggerContext = LoggerContext.getContext(false);
        Configuration config = loggerContext.getConfiguration();
        PatternLayout layout = PatternLayout.newBuilder()
                .withPattern("%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n")
                .build();
        ceLogAppender = CELogAppender.createAppender("CELogAppender", null, layout);
        ceLogAppender.start();
        config.addAppender(ceLogAppender);


        AppenderRef appenderRef = AppenderRef.createAppenderRef("CELogAppender", null, null);
        AppenderRef[] appenderRefs = new AppenderRef[]{appenderRef};
        LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.ALL,
                CELogAppenderTests.class.getName(), "true", appenderRefs, null, config, null);

        loggerConfig.addAppender(ceLogAppender, null, null);
        config.addLogger(CELogAppenderTests.class.getName(), loggerConfig);
        loggerContext.updateLoggers();
    }

    @Test
    public void testAppenderNotEmpty() {
        logger.info("A message");
        assertFalse(ceLogAppender.getEvents().isEmpty());
    }

    @AfterAll
    public static void shutdown() {
        System.out.println("shutdown");
        LogManager.shutdown();
    }
}

I can see the console output

new celogappender
start appender
event added
shutdown

but I am missing the output from my stop method:

    @Override
    public void stop() {
        super.stop();
        System.out.println("stop appender");
    }

Answer

Got the solution, I had to use/override the stop method like this

@Override
public boolean stop(long timeout, TimeUnit timeUnit) {

}