Potato_head
Potato_head

Reputation: 356

Pass context to async Logger

I am trying to log raw request/response from a http client. I am following log4j2 configurations from these logging instructions.

HttpAsync Client Dependency :- httpasyncclient (version 4.1.1)

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
    <RollingRandomAccessFile name="app-log" fileName="${log.path}/app.log"
                             filePattern="${log.path}/app-%d{yyyy-MM-dd}.gz">
        <PatternLayout>
            <pattern>[%-5level] [%X{uuid}] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n</pattern>
        </PatternLayout>
        <Policies>
            <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        </Policies>
    </RollingRandomAccessFile>
</Appenders>
<Loggers>
    <AsyncLogger name="org.apache.http.impl.conn.Wire" level="debug">
        <AppenderRef ref="app-log"/>
    </AsyncLogger>
    <AsyncRoot level="debug" includeLocation="true">
        <AppenderRef ref="app-log"/>
    </AsyncRoot>
</Loggers>
</Configuration>

It is printing fine but the threadcontext is not passing onto the wire logger.

Example :-

// with uuid, output of logger.debug(ThreadContext.getImmutableContext().toString());

[DEBUG] [c48b97f7-0094-44af-82af-3d6b43d76014] 2016-11-14 17:06:03.408 [http-bio-8080-exec-1] OutboundRequestHandler - {uuid=c48b97f7-0094-44af-82af-3d6b43d76014}

// without uuid
[DEBUG] [] 2016-11-14 17:06:03.440 [I/O dispatcher 1] headers - http-outgoing-0 >> POST /abcd.json HTTP/1.1
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> Content-Length: 2
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> Content-Type: text/plain; charset=ISO-8859-1
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> Host: 127.0.0.1:80
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> Connection: Keep-Alive
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> User-Agent: Apache-HttpAsyncClient/4.1.1 (Java/1.8.0_92)

How can I pass the ThreadContext to the logger?

Thanks.

Upvotes: 6

Views: 4242

Answers (3)

Gabriel
Gabriel

Reputation: 1751

As of v2.13.2 it is recommended to create a ContextDataProvider instead of a ContextDataInjector.

The ContextDataProvider (introduced in Log4j 2.13.2) is an interface applications and libraries can use to inject additional key-value pairs into the LogEvent's context data. Log4j's ThreadContextDataInjector uses java.util.ServiceLoader to locate and load ContextDataProvider instances. Log4j itself adds the ThreadContextData to the LogEvent using org.apache.logging.log4j.core.impl.ThreadContextDataProvider. Custom implementations should implement the org.apache.logging.log4j.core.util.ContextDataProvider interface and declare it as a service by defining the implmentation class in a file named META-INF/services/org.apache.logging.log4j.core.util.ContextDataProvider.

Upvotes: 0

user2996157
user2996157

Reputation: 31

I am not sure how relevant this is in 2019 as the asker will have surely moved on to other things. But still here it goes:

In log4j2 we have to use ThreadContext.put instead of MDC.put which is used for log4j. This will log everything perfectly. Rest everything remains same

Upvotes: 0

Remko Popma
Remko Popma

Reputation: 36754

Since the thread where the UUID was set (http-bio-8080-exec-1) is different from the thread in your application that is doing the logging (I/O dispatcher 1), they have different ThreadContext maps and the 2nd thread cannot see what the 1st thread put in its map.

Since log4j 2.7 it is possible to create a custom context data injector that can get context data from other places than from a ThreadLocal map (because that is essentially what the ThreadContext is).

That does mean that you need to create a custom facade, similar to log4j's ThreadContext, where you put key-value pairs into some data structure. I am not familiar with AsyncHttpClient but I could not find a "context" concept that allows separate threads to share data associated with the same session.

Your custom context injector implementation would take a snapshot of the key-value pairs and inject that into the LogEvent for each log message.

Upvotes: 2

Related Questions