Using Finatra, I'm trying to activate traceID
logging, but nothing ends up in Log4J2 output.
Finatra supports SLF4J MDC. SLF4J MDC is supposed to support Log4J (2?). Log4J2 is supposed to support MDC and SLF4J.
But in the end, the MDC data is always empty reaching the message construction.
I tested with Logback as the log implementation and I had the MDC logged correctly, and it is actually relying on SLF4J MDC. I do have to use log4J2 here (cannot be questioned).
Is this just not working because Log4J2 does not work correctly with SLF4J MDC?
To get it to work with Finatra, I just have to remove the LoggingMDCFilter
which pretty must only replaces the MDCAdapter
with the FinagleMDCAdapter
own implementation, backed by Finagle Contexts
.
As you noticed in your question
FinagleMDCInitializer
replaces the MDC used by the logging backend with its own.Logback uses SLF4J as their internal API (i.e. just Logback) so it will work with any
MDCAdapter
implementation installed, but all the remaining SLF4J backends won't.The same hack that permits Logback to work with Finagle can be used in Log4j2 Core. Log4j2 Core is a native implementation of Log4j2 API and it will work with any implementation of
ThreadContextMap
.We want to use a
ThreadContextMap
implementation that delegates all methods to SLF4J'sMDC
. Fortunately such an implementation is included in the Apache Log4j2 API to SLF4J Adapter (another implementation of the Log4j2 API). So we can use the following trick:add both
log4j-core
andlog4j-to-slf4j
to your application's classpath. Since now there are two implementations of the Log4j2 API available, we need to specify the one we actually want to use. We can do it by adding a file calledlog4j2.component.properties
at the root of your classpath with:in the same property file we specify that we want to use the
ThreadContextMap
implementation included inlog4j-to-slf4j
:I assume that you already have
log4j-slf4j-impl
(Apache SLF4J to Log4j2 API Adapter) on your classpath.Remark: the proposed solution assumes that
FinagleMDCInitializer
is called as soon as possible. SLF4J does not have an equivalent of thelog4j2.threadContexMap
property to force it to use a concrete implementation ofMDCAdapter
. Until Finagle replaces the implementations, your application will use theMDCAdapter
fromlog4j-slf4j-impl
that delegates everything to theThreadContextMap
, that delegates everything toMDCAdapter
, ... You'll have a guaranteed StackOverflow.Edit: If you end up with a StackOverflow, you can:
start with NOOP
ThreadContextMap
:replace the
MDCAdapter
andThreadContextMap
all in one place: