Uploaded image for project: 'logback'
  1. logback
  2. LOGBACK-1287

Breaking change? Custom appender can not be assigned to OutputStreamAppender



    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Blocker Blocker
    • 1.3.0-alpha0, 1.2.3
    • 1.2.1, 1.2.2
    • logback-core
    • None


      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:


      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) {
        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">
        <evaluator class="ch.qos.logback.classic.boolex.OnErrorEvaluator" />
        <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
          <pattern>[SOME PATTERN FOR DEBUG LOG FILE]</pattern>

      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.




            ceki Ceki Gülcü
            jackb Jack
            0 Vote for this issue
            2 Start watching this issue