I am writing a log4j appender that sends the logs to a server via http. I wanted to use HttpClient from apache-commons to keep my code nice and simple.
The problem now is that HttpClient and Co. uses log4j itself. Usually a good thing but when calling them from within a log4j appender implementation, circular references or endless loops are introduced, ultimately leading to an OutOfMemoryException.
Of course I can write what I want without any thrid-party libraries but I just wondered if there is known solution to this kind of problem?
This is a great question! It's a shame that log4j doesn't try to help you here. But we can be devious and use log4j to fix log4j! The important concept is a Diagnostic Context:
private static final String IN_APPEND_KEY = MyAppender.class.getName() + ".inAppend";
public void append(LoggingEvent e) {
if (e.getMDC(IN_APPEND_KEY) != null) return;
MDC.put(IN_APPEND_KEY, this);
try {
<your code here>
} finally {
MDC.remove(IN_APPEND_KEY);
}
}
You basically want to set a flag that will "travel" with the execution flow of your appender. This is exactly what a diagnostic context does, in theory at least. It is thread-local and inherited across threads. Carefully-written code will even preserve the context across other boundaries, such as a message queue. How cool would that be: your appender puts the log message on an HTTP request queue, the queue saves the diagnostic context and restores it when request gets run, the HTTP library logs an error, and your appender still detects the loop! It's pretty much the best thing you could ask for.