play framework logback custom layout

馋奶兔 提交于 2020-01-01 04:19:26

问题


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.


回答1:


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



回答2:


For me, I saw this error when firing up my app as follows:

./activator -Dhttp.port=9000 -Dconfig.resource=local.conf -jvm-debug 9999 run

But I got past that by using start instead of run

./activator -Dhttp.port=9000 -Dconfig.resource=local.conf -jvm-debug 9999 start

However, this created another problem; saying application.conf couldn't be found. It didn't matter that I specified the file as so:

-Dconfig.resource=local.conf

After renaming local.conf to application.conf, my custom layout class for logging is found and used.



来源:https://stackoverflow.com/questions/17845135/play-framework-logback-custom-layout

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!