With Neon the Scout Framework makes extensive use of MDC (Mapped Diagnostic Context) provided by SLF4J.
Adding a null value to this map is supported depending on the implementation.
Reading the Javadoc:
org.slf4j.MDC.put(String, String) and org.slf4j.spi.MDCAdapter.put(String, String)
Quote:The val parameter can be null only if the underlying implementation supports it.
org.slf4j.impl.Log4jMDCAdapter.put(String, String)
Quote: Log4j does not support null for the val parameter.
This can be tested with this simple Main class:
import org.slf4j.*;
public class Main {
static Logger LOGGER = LoggerFactory.getLogger(HelloLog4j.class);
public static void main(String[] args) {
MDC.put("mykey", null);
LOGGER.info("Hello {}", "World");
}
}
Produces this stacktrace:
Exception in thread "main" java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:459)
at org.apache.log4j.MDC.put0(MDC.java:150)
at org.apache.log4j.MDC.put(MDC.java:85)
at org.slf4j.impl.Log4jMDCAdapter.put(Log4jMDCAdapter.java:60)
at org.slf4j.MDC.put(MDC.java:147)
at Main.main(Main.java:8)
I do not understand why the Log4jMDCAdapter#put(..) directly delegated to org.apache.log4j.MDC#put(key, val) without doing the null check on the val parameter. This speaks against being able to exchange the logger implementation.
The only fix I see for the Scout Framework is to do the check everywhere bevor the MDC calls. Especially in DiagnosticContextValueProcessor
Does it seem reasonable?
What are the opinions?
----
I have checked some code I have in my workspace.
(closed source):
if (value == null) {
MDC.remove(key);
}
else {
MDC.put(key, value );
}
In hibernate-core-4.3.8.Final.jar PropertyPathStack:
public void push(PropertyPath path) {
pathStack.addFirst( path );
MDC.put( MDC_KEY, extractFullPath( path ) );
}
private String extractFullPath(PropertyPath path) {
return path == null ? "<no-path>" : path.getFullPath();
}
In [b]activemq-broker-5.12.1.jar[/code] I have the feeling that the code also ensures that the value is not null.
----
To work around it in the meantime, the solution is to extend with @Replace each of the IDiagnosticContextValueProvider implementation and to do the null check in the overridden value() method.
... or use logback instead of Log4j 1.x (which is end-of-life anyway).