Details
-
Bug
-
Resolution: Fixed
-
Blocker
-
1.2.1, 1.2.2
-
None
Description
With the release of logback 1.2.1 our custom appender does not work anymore and Joran fails with the error below:
INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property ERROR in ch.qos.logback.core.joran.util.PropertySetter@434f3900 - A "com.example.logging.logback.extensions.DebugFileDumper" object is not assignable to a "ch.qos.logback.core.OutputStreamAppender" variable. The class "ch.qos.logback.core.OutputStreamAppender" was loaded by [startJarLoader@2d95ebec] whereas object of type "com.example.logging.logback.extensions.DebugFileDumper" was loaded by [startJarLoader@2d95ebec].
I think the issue has been introduced by commit:
https://github.com/qos-ch/logback/commit/d3d704c12e7b8e6503187744ac2200c244088c63
which makes LayoutWrappingEncoder assume that it is always owned by an OutputstreamAppender:
However our custom Appender extends AppenderBase and uses composition to use two FileAppenders internally. The encoder of one of those FileAppenders can be configured in logback.xml while the other has a fixed encoding. Basically the Java code delegates setEncoder() to a FileAppender. Code roughly looks like:
public class DebugFileDumper extends AppenderBase<ILoggingEvent> { // writes a debug-timestamp.log from a cyclic buffer private FileAppender<ILoggingEvent> debugBufferFileDumper; // writes a debug-timestamp.meta containing corresponding meta infos stored in MDC in an easy to parse key=value format for further processing by external tools. private FileAppender<ILoggingEvent> mdcFileDumper; // ... additional properties public DebugFileDumper() { mdcFileDumper.setEncoder(new MdcOnlyEncoder()); } public void setEncoder(Encoder<ILoggingEvent> encoder) { debugBufferFileDumper.setEncoder(encoder); } public Encoder<ILoggingEvent> getEncoder() { return debugBufferFileDumper.getEncoder(); } // .. additional methods }
With configuration like:
<appender name="debugDumper" class="com.example.logging.logback.extensions.DebugFileDumper"> <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator"> <key>SESSION_ID</key> <defaultValue>server</defaultValue> </discriminator> <evaluator class="ch.qos.logback.classic.boolex.OnErrorEvaluator" /> <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker"> <bufferSize>128</bufferSize> <maxComponents>128</maxComponents> <timeout>1800000</timeout> </cyclicBufferTracker> <folder>${logback.logs}/dumps</folder> <encoder> <pattern>[SOME PATTERN FOR DEBUG LOG FILE]</pattern> </encoder> </appender>
I think our implementation strategy is valid and the assumption made in the mentioned commit, that an encoder configuration block always belongs to an OutputStreamAppender, is a bit too strict. Basically composition/delegation pattern hasn't been taken into account.
Currently we would need to rewrite our appender in order to make it work with Logback 1.2.1+, so I thought I should let you know about that implicit breaking change. Maybe it was not intended on your side and you can relax the assumption to fix our issue.