Search code examples
javalog4jlog4j2pattern-layout

PatternLayout not substituting values from ThreadContext in Java


I am tying to create a PatternLayout object in Java code that will have its values substituted from the ThreadContext, using the %X (and %d) placeholder.

private PatternLayout patternLayout = PatternLayout.newBuilder()
                                                   .withPattern("op1=%X{op1}|op2=%X{op2}|timestamp=%d{HH:mm:ss.SSS}")
                                                   .build();

I have also implemented the Log4J Message interface:

private final PatternLayout pattern;

MyLoggingMessage(final PatternLayout pattern) {
    this.pattern = pattern;
}

@Override
public String getFormattedMessage() {

    // I have also tried return pattern.getContentFormat();
    return pattern.toString();
}

However, when this is recorded in Graylog, the values have not been substituted out, and remains op1=%X{op1}|op2=%X{op2}|timestamp=%d{HH:mm:ss.SSS}. However, if I use an XML implementation of the same pattern in my appender,...

<PatternLayout pattern="op1=%X{op1}|op2=%X{op2}|timestamp=%d{HH:mm:ss.SSS}" />

it all gets substituted out. How can I get log4j to evaluate the pattern in Java? From what I can see, both methods just set the pattern field.


Solution

  • So this worked for me:

    private final StringMap params;
    
    MyLoggingMessage(final PatternLayout pattern) {
        this.pattern = pattern;
        this.params = (StringMap) ThreadContext.getContext();
    }
    
    @Override
    public String getFormattedMessage() {
    
        LogEvent logEvent = Log4jLogEvent.newBuilder()
                                         .setContextData(params)
                                         .build();
    
        return pattern.toSerializable(logEvent);
    }