19

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?

user2833557
  • 677
  • 5
  • 10

2 Answers2

13

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.

agabor
  • 662
  • 6
  • 7
  • Thanks agabor, seems to be the way to go then ? could you provide some details on how to do that, please ? – Antonin Oct 01 '16 at 22:13
  • The basic idea is that you create a stand-alone project for your custom logger and use it as a dependency in your Play project. As this is an old issue I'm not sure if it's still a problem with the latest Play versions. Even if it is there might be another workaround. – agabor Oct 03 '16 at 08:59
  • Thanks agabor, I will try that. this is still an issue with current versions of play (2.5.x) – Antonin Oct 03 '16 at 21:18
1

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.

archydave
  • 11
  • 1