0
votes

I want to log Request/Response of my server in log files. I am using Springboot + jersey 2.x + log4j2. I registered jersey's LoggingFeature like this -

jerseyConfig.register(
    new LoggingFeature(
          java.util.logging.Logger.getLogger(
                     LoggingFeature.DEFAULT_LOGGER_NAME),
          java.util.logging.Level.SEVERE,
          LoggingFeature.Verbosity.PAYLOAD_ANY,
          Integer.MAX_VALUE)
);

log4j2.xml

<!-- Jersey logger -->
<AsyncLogger name="org.glassfish" level="all" additivity="false">
    <AppenderRef ref="Console" level="off" />
    <AppenderRef ref="RollingFileIO" level="error" />
</AsyncLogger>

In pattern, I am injecting transaction-id with help of log4j2's ThreadContext. I have log4j-jul 2.1 in my pom.xml, and I am running it with

-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager .

Things are working fine, only problem is, in jersey's logs, I am unable to insert transaction id. I tried utils logging with my custom code, and I am able to put transaction-id in it. But by the time jersey writes these logs, ThreadContext gets cleared and transaction-id values comes empty.

2
What do you mean "unable to insert transaction id"? Error? Unclear on what API to use (or whether API exists)?Remko Popma
I meant, by the time jersey writes these logs, ThreadContext gets cleared by my code. For any http request, I generate transaction-id and put it in ThreadContext and clear it when response goes out. Jersey writes before and after of these events. I tried java.util.logging by my own logging, and it successfully puts transaction-id in logs.theGamblerRises

2 Answers

0
votes

If the log flow is JUL->log4j2->FooAppender->Layout->ThreadContext.pop then

Per Including the ThreadContext when writing logs:

The PatternLayout provides mechanisms to print the contents of the ThreadContext Map and Stack.

  • Use %X by itself to include the full contents of the Map.
  • Use %X{key} to include the specified key.
  • Use %x to include the full contents of the Stack.

If the flow is log4j2->JUL->FooHandler->Formatter->ThreadContext.pop then you have to install or create a formatter that is aware of the ThreadContext. You also have make sure in this configuration that log4j2->ThreadContext.pop->JUL->FooHandler->Formatter is not happening as that would forget all of the information before it gets to JUL.

All of the examples in the documentation show the ThreadContext is set prior to invoking the logger. Which means you have to set the ThreadContext prior to any Jersey code execution.

0
votes

I haven't looked at Jersey in detail but from the problem description it seems that it has a thread model that makes working with ThreadContext difficult.

Fortunately Log4j 2.7 offers a facility to let you inject key-value pairs (like ID) into log events from another source than the ThreadContext. This was introduced to help with asynchronous frameworks like Finagle, so it may be useful for Jersey as well.

The Log4j2 manual briefly mentions this feature in the section on Custom ContextDataInjectors.

If you want to use this facility you need to write a custom ContextDataInjector and tell Log4j to use that injector instead of the default one by specifying a ContextDataInjectorFactory. Your custom injector needs to get the key-value pairs from somewhere. In Jersey's case, would RequestContext.getProperty and setProperty be appropriate?