9

How to add MDC variables in the json log generated by JsonLayout of log4j2. I've used KeyValuePair tag to add properties like host name into the log, but I didn't found any way to add MDC variables into it. In pattern layout I used %X{traceId} but I'm sure JsonLayout can't parse those conversion chars(As far as I know conversion chars are used by pattern layout only). I went into source code of JsonLayout but didn't found function which actually puts all of the data into the log message.

Thank you.

omjego
  • 373
  • 2
  • 5
  • 15

1 Answers1

14

What you're looking for is a log4j2 lookup. It sounds like you're interested specifically in the Context Map Lookup as you mentioned MDC (which is now called ThreadContext in log4j2 by the way).

Here is a simple example:

package example;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class ThreadContextExample {

    private static final Logger log = LogManager.getLogger();

    public static void main(String[] args) {
        ThreadContext.put("myKey", "myValue");
        log.info("Here's a message!");
    }
}

Here is the log4j2.xml configuration:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <JsonLayout compact="false" eventEol="false" stacktraceAsString="true">
                <KeyValuePair key="myJsonKey" value="${ctx:myKey}"/>
            </JsonLayout>
        </Console>

    </Appenders>

    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

and finally some sample output (shortened for readability):

{
  "thread" : "main",
  "level" : "INFO",
  "loggerName" : "example.ThreadContextExample",
  "message" : "Here's a message!",
  ...
  "myJsonKey" : "myValue"
}
D.B.
  • 4,523
  • 2
  • 19
  • 39
  • 1
    There is one problem though. Not all of the log messages should contain MyJsonKey. So in that case the log gets printed and it value field comes out to be "{ctx:mykey}", which looks very bad. Is there any way we can add parameters to json log dynamically ? @D.B. – omjego Oct 11 '18 at 15:09
  • If you don't want the key printed in the log at all you probably want to look at [RoutingAppender](https://logging.apache.org/log4j/2.x/manual/appenders.html#RoutingAppender) and use two different appender configurations within the `Routes` - one with the key, the other without. Also read the [log4j2 FAQ page](https://logging.apache.org/log4j/2.x/faq.html#separate_log_files), there is a good example of `RoutingAppender` in there. – D.B. Oct 11 '18 at 17:15
  • 4
    A better way to use your value field is $${ctx:myKey:-}. The json key will exist even with empty value, however the ctx:myKey will not appears in logs, just an empty string. – gaellm Aug 25 '21 at 08:36
  • Is it necessary to do a `ThreadContext.clearMap();` just like we used to do a `MDC.clear()` at the end? – Sankalp Apr 27 '23 at 17:05