Reputation: 1429
How do I print a key/value pair on a log4j entry only if the value is set on MDC?
For example, I currently have the following pattern:
%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - client=%X{client} %m%n
I'd like to print the "client=" part only if there is a value on MDC for this key.
For example, when starting my program, there will be no client logged in, so logs would be recorded using this pattern:
%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
However, after the client has logged in (and after I have set the MDC with a "client" key), I need to print it using the following:
%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - client=%X{client} %m%n
Is there such "conditional pattern" on log4j?
Thank you
Upvotes: 32
Views: 12312
Reputation: 19880
A suggested hack to keep key with value as MDC value helps to bind key name to some constant in code. But this is not good for microservices when e.g. header is resent to other service and key name gets duplicated.
There is a clean Logback pattern-logic solution that allows to achieve this:
%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %replace( client=%mdc{client}){' client=$', ''} %m%n
Upvotes: 3
Reputation: 387
I had a similar requirement recently and while other solutions can do the trick in many cases, sometimes more control is needed. For example, I had to produce something like this: A:B,C
where both A
and B
were optional. I was unable to find a solution that would not leave a comma in front of C
using just a pattern. So I ended up creating a custom converter.
In OP's case, we could introduce a new token into the pattern, for example %client
(assuming Log4j2).
@Plugin(name = "ClientConverter", category = PatternConverter.CATEGORY)
@ConverterKeys({ "client" })
public class ClientConverter extends LogEventPatternConverter {
private static final ClientConverter INSTANCE = new ClientConverter();
private ClientConverter() {
super("ClientConverter", null);
}
public static ClientConverter newInstance(String[] options) {
return INSTANCE;
}
@Override
public void format(LogEvent event, StringBuilder toAppendTo) {
var context = event.getContextData();
Optional.ofNullable(context.getValue("client"))
.ifPresent(client -> toAppendTo.append("client=").append(client));
}
}
Upvotes: 1
Reputation: 1018
There is a %notEmpty
pattern in Log4j2 which allows you to achieve exactly this.
%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %notEmpty{client=%X{client} }%m%n
Upvotes: 43
Reputation: 1429
I endend up using xav's suggestion.
I removed the "client=" string from the log4j pattern and appended it everytime I added an entry to MDC. It's not the most beautiful solution but it worked great!
For example, where I otherwise would use
MDC.put("client", client.getId());
I am now using:
MDC.put("client", "client="+client.getId().toString());
Upvotes: 13