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.
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:
jar
file and put that jar
file into the lib/
directory of your projectIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With