However, this has a strong drawback: filename and line numbers in the log which should tell me the origin of the log calls instead show me my wrapper class. From logback's perspective the wrapper is the caller; from my perspective the wrapper should be invisible.
The culprit is
CallerData.isDirectlyInvokingClass(String, String)
. It tells logback if a given stack frame is internal to logback or from the calling application. It is static
and logback has no hooks for changing its behavior. What to do?The hack:
public class Wrapper { static { new MockUpEnter the clever jmockit library sitting at the high end of the testing mock library pile up (or deep end, if you prefer). Jmockit is not the easiest library to use, but is has more code-fu per line than most other swiss-army knives.() { CallerData it; @Mock(reentrant = true) public boolean isDirectlyInvokingClass( final String currentClass, final String fqnOfInvokingClass) { return it.isDirectlyInvokingClass( currentClass, fqnOfInvokingClass) || currentClass.equals(Wrapper.class.getName()); } }; } // Rest of class }
I replace the static method in logback with my own when my wrapper class is loaded. I even get a handle (it) to the original method so I may forward appropriately.
This is not my first try at a solution to wrapping logback. Nor my second. Nor my third. But it is the only one so far which:
- Works
- Looks like Java
- Is compact and limited to the wrapper class
- Can be explained to others (mostly)
- Can be maintained (by some)
Do watch out for:
- Running the application right in the presence of jmockit
- The obligatory AOP warning for the "it" trick
2 comments:
Why no just use SLF4J directly?
The application I'm working on which has this issue is already built on an internal logging library with its own APi. I'm working to swap out the underlying JCL/log4j with SLF4J/logback but not (yet) update the thousands of logging call sites. Painful but necessary.
Post a Comment