The MDC is not available when writing the access log. The MDC variables are removed by the filter (post-processing) running way before the access log.It is not a solution just to not remove the MDC variables, as you wouldn't want the MDC variables to stay around for the next request.
In stead you may write a few classes for handling this.First, write a class for holding your variables. For example:
public class AccessLogger {
private static ThreadLocal<AdditionalInfo> currentInfo = new ThreadLocal<>();
public static String getAndRemoveAdditionalInfo() {
AdditionalInfo additionalInfo = currentInfo.get();
currentInfo.remove();
return additionalInfo.getInfo();
}
public static void setAdditionalInfo(String info){
currentInfo.set(new AdditionalInfo(info));
}
public static final class AdditionalInfo {
private String info;
public AdditionalInfo(String info) {
super();
this.info = info;
}
public String getInfo() {
return info;
}
}
}
Secondly, use that class in a custom access converter:
public class AdditionalInfoConverter extends AccessConverter {
@Override
public String convert(IAccessEvent event) {
String info = AccessLogger.getAndRemoveAdditionalInfo();
return info!=null ? info : "-";
}
}
Thirdly, add the customer converter to a new wrapper class. This class adds %X to get the additional info.It would be nice if Logback supported a callback to extend PatterLayout, however, this is how it can be done without changing the Logback source code.
public class AccessLogLayoutWrapper extends PatternLayoutEncoderBase<IAccessEvent> {
@Override
public void start() {
PatternLayout patternLayout = new PatternLayout();
patternLayout.getDefaultConverterMap().put("X", AdditionalInfoConverter.class.getName());
patternLayout.setContext(context);
patternLayout.setPattern(getPattern());
patternLayout.start();
this.layout = patternLayout;
super.start();
}
}
Finally, use some filter to set the additional info in AccessLogger. ... AccessLogger.setAdditionalInfo( userName);
|