9
votes

Here is the specific issue I am encountering. I am using SLF4J Logger (The type of the variable logger below)

//After adding to a map
logger debug ("Adding {} = {}", key, value)

Here is what mouse hover in eclipse (and the compiler) tell me.

ambiguous reference to overloaded definition, both method debug in trait Logger of type (x$1: String, x$2: Object*)Unit and method debug in trait Logger of type (x$1: String, x$2: Any, x$3: Any)Unit match argument types (String,String,String)

I understand why they are ambiguous. I am certainly not arguing with the compiler :). I want to simply know how seasoned programmers solve this issue.

Here are the alternatives I can use

  1. Create and array , and ride the Object* definition

    logger debug ("Adding {} = {}", Array(key, value):_*)

  2. Cast to Any

    logger debug ("Adding {} = {}", key.asInstanceOf[Any], value.asInstanceOf[Any])

Neither approach is particularly appealing. Does the community have a better approach or suggestions for me?

Many thanks!

2
Looks like it might be a known issue - see hereShadowlands
I think that's it. Thanks for your help @Shadowlands! If you could post that as an answer, I can mark the question solved and we can help the community.Prashant
With string interpolation, i just always use logger debug (s"Adding $key = $value) these data. Since string interpolation is compile time, it's probably more efficient as wellArne Claassen
@ArneClaassen sorry for my ignorance. But what is the "s" in your code?Prashant
Scala 2.10 added string interpolation. "s" and others like it are explained here: docs.scala-lang.org/overviews/core/string-interpolation.htmlArne Claassen

2 Answers

12
votes

I would use

logger.debug("Adding {} = {}", key, value: Any)

Alternatively following can be used:

logger.debug("Adding {} = {}", Array(key, value):_*)

Please pay attention to :_*. Should you omit these symbols and it will call Object* method providing only 1 argument, which will be an array.

7
votes

First off a nod of credit to @Shadowlands, @ArneClaassen and @OlgeRudenko. As mentioned in the comments, this does seem to be known issue. That stopped me from trying to "solve" it. The next thing to do was to find a good work around that did not break Scala idioms.

With these constraints in mind I chose to go with String Interpolation as suggested above. I also switched to scala-logging. Quoting from their GitHub/README,

Scala Logging is a convenient and performant logging library wrapping SLF4J. It's convenient, because you can simply call log methods without checking whether the respective log level is enabled:

logger.debug(s"Some $expensive message!")

It's performant, because thanks to Scala macros the check-enabled-idiom is applied, just like writing this more involved code:

if (logger.isDebugEnabled) logger.debug(s"Some $expensive message!")

Thanks all! As far as I am concerned, this is resolved. If the commentators can post their answers, I will be happy to acknowledge them.

As always, feels good to be standing on the shoulders of friendly giants!

PS: I just verified that there is no execution cost to String interpolation if you are using scala-logging. My verification method was crude but effective.

    log.debug{ 
        {
          throw new IllegalAccessException("This should not have been called with debug off!")
        }
        s"Added Header ${name}:${headerValue}"
      }

Sure enough, when I set my log to DEBUG, the exception is thrown, as expected , but vanishes when I set it to a level higher. And yes, I have already removed the IllegalAccessException part :).