Reputation: 1582
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