Play fails to load custom log back appender

2019-04-03 14:08发布

问题:

I have created a custom logback appender. But play gives a ClassNotFound exception for the appender.

Following is my appender

package log

import ch.qos.logback.core.AppenderBase
import ch.qos.logback.core.UnsynchronizedAppenderBase
import ch.qos.logback.core.spi.ContextAwareBase
import log.model.LogMessage
import data.OrganizationDao
import log.dao.LogDao
import ch.qos.logback.core.status.Status

class MongoAppender extends ContextAwareBase {
  private def add(level:Int, msg: String, ex: Throwable) = {
    val message = ex match {
      case null => LogMessage(None, level, msg, null, null, new Array[String](0))
      case _ => LogMessage(None, level, msg, ex.getClass().getName(), ex.getMessage(), new Array[String](0))
    }

    LogDao.save(message)

  }
  override def addStatus(status:Status) = {
    add(status.getLevel(), status.getMessage(), status.getThrowable())
  }

}

The following is my logger.xml

<configuration>

    <conversionRule conversionWord="coloredLevel"
        converterClass="play.api.Logger$ColoredLevel" />

    <appender name="Mongo" class="log.MongoAppender">

    </appender>



    <logger name="play" level="INFO" />
    <logger name="application" level="INFO" />

    <root level="ERROR">
        <appender-ref ref="Mongo" />
    </root>

</configuration>

I am getting the following stacktrace

Caused by: java.lang.ClassNotFoundException: log.MongoAppender
        at      at java.net.URLClassLoader$1.run(Unknown Source)
        at      at java.net.URLClassLoader$1.run(Unknown Source)
        at      at java.security.AccessController.doPrivileged(Native Method)
        at      at java.net.URLClassLoader.findClass(Unknown Source)
        at      at java.lang.ClassLoader.loadClass(Unknown Source)
        at      at java.lang.ClassLoader.loadClass(Unknown Source)
        at      at ch.qos.logback.core.util.OptionHelper.instantiateByClassNameA
ndParameter(OptionHelper.java:60)

I have checked that the appender class does compile and also checked the compiled byte code. Why does not play pick it up?

回答1:

It seems that play's dynamically compiled classes in dev mode are not available for logback. I'm struggling with the same issue. Putting my custom appender to a separate jar file works for me. I assume in prod with staged final jar files this should not be a problem.



回答2:

Although the solution of adding a separate jar file works, I found another solution which adds the benefit of accessing your uri as defined in your application.conf file.

Create an EagerSingleton in your Module. This will get called during startup. Inside this, construct your MongoDB Appender and add it to the logger you want to log to MongoDB. The benefit is that you can inject your Configuration into this singleton and then access config settings to pass on to your MongoDB Appender.