Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

play framework logback custom layout

I am trying to use a custom layout class for play framework 2.0 logback logging.

First, I defined a custom layout class in package utils:

package utils;

public class MonitorLayoutForLogback extends LayoutBase<ILoggingEvent> {
...
}

In my conf/logging.xml file, I put:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="utils.MonitorLayoutForLogback">
                             <param name="programName" value="uowVisualizer" />
                             <param name="serviceGroup" value="shared" />
                             <param name="serviceIdentifier" value="uowVisualizer" />
            </layout>
        </encoder>
    </appender>

but when I run within play, e.g.,

play run

I see:

14:20:18,387 |-ERROR in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Could not create component [layout] of type [utils.MonitorLayoutForLogback] java.lang.ClassNotFoundException: utils.M
onitorLayoutForLogback
    at java.lang.ClassNotFoundException: utils.MonitorLayoutForLogback
    at      at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at      at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at      at java.security.AccessController.doPrivileged(Native Method)
    at      at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at      at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at      at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at      at sbt.PlayCommands$$anonfun$53$$anonfun$55$$anon$2.loadClass(PlayCommands.scala:535)
    at      at ch.qos.logback.core.util.Loader.loadClass(Loader.java:124)
    at      at ch.qos.logback.core.joran.action.NestedComplexPropertyIA.begin(NestedComplexPropertyIA.java:100)
    at      at ch.qos.logback.core.joran.spi.Interpreter.callBeginAction(Interpreter.java:276)
    at      at ch.qos.logback.core.joran.spi.Interpreter.startElement(Interpreter.java:148)
    at      at ch.qos.logback.core.joran.spi.Interpreter.startElement(Interpreter.java:130)
    at      at ch.qos.logback.core.joran.spi.EventPlayer.play(EventPlayer.java:50)
    at      at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:157)
    at      at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:143)
    at      at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:106)
    at      at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:56)
    at      at play.api.Logger$$anonfun$configure$8.apply(Logger.scala:248)
    at      at play.api.Logger$$anonfun$configure$8.apply(Logger.scala:247)
    at      at scala.Option.map(Option.scala:145)
    at      at play.api.Logger$.configure(Logger.scala:247)
    at      at play.api.Application$class.$init$(Application.scala:266)

So, play can't find the layout class I created. How do I put the layout class on the class path?

Note that I also tried staging the project via,

play clean compile stage

and then started the project via

target/start

Starting the project from the packaged version, I don't see the above missing class error. However, I also never see any output, nor do I even see the class constructed. I added System.out.println statements to each constructor for this class as follows, to verify whether or not the class was being constructed:

    public MonitorLayoutForLogback() {
        System.out.println("MonitorLayoutForLogback Constructor without arguments");
    }

    public MonitorLayoutForLogback(String program) {
        System.out.println("MonitorLayoutForLogback Constructor with program "+program);
        _program = program;
    }

    public MonitorLayoutForLogback(String program, String sGroup, String sid) {
        System.out.println("MonitorLayoutForLogback Constructor with program "+program+" sGroup "+sGroup+" sid "+sid);
        _program = program;
        MonitoringInfo.setServiceGroup(sGroup);
        MonitoringInfo.setServiceIdentifier(sid);
    }

I'm a newbie to logback configuration, so I'm sure I'm missing something obvious. Thanks for the help.

like image 293
Chris Jones Avatar asked Jul 24 '13 21:07

Chris Jones


1 Answers

The issue you are seeing stems from how logback uses the class loader for classes configured as filter, layout, encoder etc.

The issue is that for all dependencies, including logback, the classes are loaded in a DependencyClassloader which is stable, while the project code is loaded in a ReloadableClassloader which is a child of the stable class loader and is discarded whenever project source code changes.

Since logback doesn't allow to pass a custom classloader, nor does it lookup the context classloader, it tries to resolve project classes in the stable classloader and fails to find project classes.

There is a declined pull request to change that behaviour in logback There is evidence there are no plans to change that behaviour

There are two workarounds:

  • If you are using sub-projects put your class into a sub-project
  • If you are not using sub-projects package your class into a jar file and put that jar file into the lib/ directory of your project
like image 72
Th 00 mÄ s Avatar answered Sep 21 '22 18:09

Th 00 mÄ s