I'm using logback for logging of a Java web service app, using embedded Jetty. The logging works as expected based on the logback.xml file... all except for some logs originating in Java, but showing up in the jsvc output to stderr.
I would like specifically to see all my Java-generated logs with millisecond timestamps to match my other logs, and ones showing up in the jsvc stderr output are only down to the second.
The jsvc stdout logs are mostly generated from Jersey and I see my own code referenced as objects are registered with Guice, which gives me hope that it can be controlled through logback. I don't understand what causes those logs to show up in jsvc's stderr output rather than in the logback catchall. Has anyone solved a similar problem in their code or configuration when using jsvc?
The solution required changes in a few places, and was largely an slf4j configuration issue. My app has numerous dependencies, and they introduce a variety of logging implementations. Slf4j was designed to corral them all together, and the process is often just an easy drop-in of a jar, but java.util.logging takes a bit more effort.
The slf4j Bridging Legacy APIs page describes (mostly) how to wire up the JUL dependency introduced by Jersey. I had already included the jul-to-slf4j.jar, but it wasn't wired up correctly. I needed to execute SLF4JBridgeHandler.install()
in the initialization of my app. In addition, the page cautions about negative performance implications unless I also include the following in my logback.xml file:
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
That got me most of the way there, but introduced duplication of log events-- one went to slf4j and the other continued to stderr. Google directed me to an article in Claus Neilsen's Blog, "Bridging java.util.logging to SLF4J". This contained a helpful snippet of code:
// Jersey uses java.util.logging - bridge to slf4
java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler[] handlers = rootLogger.getHandlers();
for (int i = 0; i < handlers.length; i++) {
rootLogger.removeHandler(handlers[i]);
}
SLF4JBridgeHandler.install();
With that in place, the Jersey logs that were showing up in my jsvc stderr output are now showing up with the rest of my logs, nicely formatted, as directed by logback.xml.