Пользовательский макет

Я пытаюсь использовать собственный класс макета для ведения журнала журналов play framework 2.0.

Сначала я определил собственный класс макета в utils пакета:

package utils;

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

В моем файле conf/logging.xml я помещаю:

<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>

но когда я запускаю внутри игры, например,

play run

Я вижу:

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)

Итак, игра не может найти класс макета, который я создал. Как поместить класс макета в путь класса?

Обратите внимание, что я также попытался организовать проект через

play clean compile stage

а затем начал проект через

target/start

Запуск проекта из упакованной версии, я не вижу вышеупомянутую ошибку класса. Тем не менее, я также никогда не вижу выхода, и даже не вижу, как построил класс. Я добавил инструкции System.out.println каждому конструктору для этого класса следующим образом, чтобы проверить, был ли построен класс:

    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);
    }

Я новичок в настройке logback, поэтому я уверен, что мне не хватает чего-то очевидного. Спасибо за помощь.

Ответ 1

Проблема, которую вы видите, связана с тем, как logback использует загрузчик классов для классов, настроенных как фильтр, макет, кодировщик и т.д.

Проблема заключается в том, что для всех зависимостей, включая logback, классы загружаются в стабильный DependencyClassloader, в то время как код проекта загружается в ReloadableClassloader который является дочерним по отношению к загрузчику стабильных классов и отбрасывается при каждом изменении исходного кода проекта.

Поскольку logback не позволяет передавать пользовательский загрузчик классов и не ищет контекстный загрузчик классов, он пытается разрешить классы проекта в стабильном загрузчике классов и не может найти классы проекта.

Существует отклоненный запрос на изменение, чтобы изменить это поведение при входе в систему. Существуют доказательства того, что нет планов изменить это поведение.

Есть два обходных пути:

  • Если вы используете подпроекты, поместите свой класс в подпроект
  • Если вы не используете подпроекты, упакуйте свой класс в файл jar и поместите этот файл jar каталог lib/ вашего проекта.

Ответ 2

Для меня я увидел эту ошибку при запуске приложения следующим образом:

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

Но я прошел мимо этого, используя start вместо run

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

Однако это создало еще одну проблему; не удалось найти application.conf. Не имело значения, что я указал файл так:

-Dconfig.resource=local.conf

После переименования local.conf в application.conf наш пользовательский класс макета для ведения журнала найден и используется.