Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I leveraging SLF4J varargs logging in Play2.1 framework?

SLF4J's varargs on the logging calls are quite useful in my Java work

Logger log = LoggerFactory.getLogger( getClass() );
log.debug( "Hello, {}.  The current time is {}", "robert", new Date() );

Attempting to do this simple example in Play 2.1 Framework/Scala and I run into the compiler rejecting me.

import play.api._
import play.api.mvc._
import org.slf4j.LoggerFactory

object Application extends Controller {
  val log: org.slf4j.Logger = LoggerFactory.getLogger(getClass())

  def hb = Action {
    val message = makeMessage()
    // COMPILER HATES THIS:  ambiguous reference compiler error here
    log.info("Hello {}.  The current time is {}", "robert", new java.util.Date() )
    Ok(message)
  }
  def makeMessage(): String = { return "stuff" }
}

[dm2-server] $ compile
[info] Compiling 2 Scala sources to /Users/bobk/work/dm2-server/target/scala-2.10/classes...
[error] /Users/bobk/work/dm2-server/app/controllers/Application.scala:16: ambiguous reference to overloaded definition,
[error] both method info in trait Logger of type (x$1: String, x$2: <repeated...>[Object])Unit
[error] and  method info in trait Logger of type (x$1: String, x$2: Any, x$3: Any)Unit
[error] match argument types (String,String,java.util.Date)
[error]     log.info("Hello {}.  The current time is {}", "robert", new java.util.Date() )
[error]         ^
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 1 s, completed Jun 6, 2013 10:54:41 AM

What is that error and how do I overcome it to call through to the SLF4J API? If I can't do that, how can I use the Play 2.1 Logging Framework to get varargs on my logging calls? Something is not right in Scala-land.

like image 898
Bob Kuhar Avatar asked Jun 06 '13 17:06

Bob Kuhar


People also ask

How do you change the log level in SLF4J?

When using log4j, the Logger. log(Priority p, Object message) method is available and can be used to log a message at a log level determined at runtime. We're using this fact and this tip to redirect stderr to a logger at a specific log level. slf4j doesn't have a generic log() method that I can find.

Does SLF4J depend on log4j?

SLF4j is a logging facade, it doesn't do logging by itself instead depends on the logging component like LOG4j, Logback or JLogging. SLF4j is an API designed to give generic access to many logging frameworks.

How does SLF4J binding work?

Bindings are basically implementations of a particular SLF4J class meant to be extended to plug in a specific logging framework. By design, SLF4J will only bind with one logging framework at a time. Consequently, if more than one binding is present on the classpath, it will emit a warning.


2 Answers

What version of SLF4J are you using? If you can go back to 1.6.6 or later, you can avoid this issue in ambiguity. Those two signatures unfortunately look the exact same to scala and the compiler can't seem to differentiate which one you mean. The common suggestion is to roll back to a version of SLF4J (if even possible for you) where this overloaded method ambiguity will not exist. More info can be found at the links below:

https://groups.google.com/forum/?fromgroups#!topic/scala-language/ms4IVIu-xGw

https://github.com/typesafehub/scalalogging/issues/16

like image 141
cmbaxter Avatar answered Nov 01 '22 06:11

cmbaxter


The "quick fix" for this is as follows:

Just force the last argument to be type Any and that resolves the compiler's issue(s) (and makes for slightly less code...)

logger.debug("hello {} / {} ", "Hello", "World":Any)

Or in your case:

log.info("Hello {}.  The current time is {}", "robert", new java.util.Date():Any)
like image 35
Techmag Avatar answered Nov 01 '22 07:11

Techmag