EasterBunnyBugSmasher
EasterBunnyBugSmasher

Reputation: 1582

adding another log record with context information

I'm running an application in wildfly 26. When exceptions are logged, I want to add another log line with information coming from a ThreadLocal inside my application (it contains information like the called REST-Endpoint and user info). So my idea was to wrap a Logging Handler and publish another message. Following is an incomplete solution, I'm not yet filtering for exceptions and not adding the correct message yet.

public class WrappingHandler extends Handler {

    private final Handler wrapped;

    public WrappingHandler(Handler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public void publish(LogRecord record) {
        LogRecord additional = new LogRecord(record.getLevel(), "additional message");
        additional.setLoggerName(record.getLoggerName());
        wrapped.publish(additional);
        wrapped.publish(record);
    }

    @Override
    public void flush() {
        wrapped.flush();
    }

    @Override
    public void close() throws SecurityException {
        wrapped.close();
    }

}

and I wrapped the current Handlers in an initializer:

@Singleton
@Startup
public class LoggingInitializer {

    private final Logger logger = Logger.getLogger(LoggingInitializer.class.getName());

    @PostConstruct
    public void init() {
        wrapHandlers(LogContext.getSystemLogContext().getLogger(""));
        logger.info("logging initialized");
    }


    private void wrapHandlers(Logger logger) {
        Handler[] handlers = logger.getHandlers();
        for (Handler handler : handlers) {
            logger.removeHandler(handler);
            logger.addHandler(new WrappingHandler(handler));
        }
    }
}

That worked well... until I redeployed the application. In that case, the wrapping handler was wrapped again, resulting in two additional log messages instead of one. So I improved the wrap method:

private void wrapHandlers(Logger logger) {
    Handler[] handlers = logger.getHandlers();
    for (Handler handler : handlers) {
        if (! handler instanceof WrappingHandler) {
            logger.removeHandler(handler);
            logger.addHandler(new WrappingHandler(handler));
        }
    }
}

But that didn't work. Since the ear was redeployed, the WrappingHandler from the old ear was not the same as the WrappingHandler from the new ear. So I had further complicate it:

private void wrapHandlers(Logger logger) {
    Handler[] handlers = logger.getHandlers();
    for (Handler handler : handlers) {
        logger.removeHandler(handler);
        Class<?> oldClass = handler.getClass();
        if (oldClass.getName().equals(WrappingHandler.class.getName())) {
            try {
                Field wrappedField = oldClass.getDeclaredField("wrapped");
                wrappedField.setAccessible(true);
                Handler wrappedHandler = (Handler) wrappedField.get(handler);
                logger.addHandler(new WrappingHandler(wrappedHandler));
            } catch (IllegalAccessException | NoSuchFieldException x) {
                x.printStackTrace();
            }
        }
        else {
            logger.addHandler(new WrappingHandler(handler));
        }
    }
}

As you can see, it turned ugly. So I'm currently not sure if I'm following the right path. It seems to me that my solution is dirty. I could improve it by unwrapping the handlers in a @PreDestroy method. Would that be called in a guaranteed way when redeploying? Would that make it cleaner? Or is there a much simpler solution to my task?

Upvotes: 0

Views: 29

Answers (0)

Related Questions