11

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!

6
  • 2
    Looks like it might be a known issue - see here Commented Sep 2, 2015 at 21:35
  • 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. Commented Sep 2, 2015 at 21:43
  • 2
    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 well Commented Sep 2, 2015 at 23:47
  • @ArneClaassen sorry for my ignorance. But what is the "s" in your code? Commented Sep 3, 2015 at 1:17
  • 2
    Scala 2.10 added string interpolation. "s" and others like it are explained here: docs.scala-lang.org/overviews/core/string-interpolation.html Commented Sep 3, 2015 at 2:01

2 Answers 2

16

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, @OlegRudenko you are correct in pointing out the mistake. I did not type that properly. I am guessing when I wrote Object*, I must have mentally checked off _* . Anyway a mistake is a mistake. Thanks for correcting it. I will correct my original question.
Seems that the first approach is preferable over the second which creates an array even if the log level is disabled. Perhaps wrap that version in a check that debug is enabled?
Use scala-logging. :) The answers just to show how to resolve ambiguous method references. Concerning performance: my experience shows that you should concentrate on readability of the code and optimize performance ONLY if you really see the need.
7

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 :).

1 Comment

Thanks! I forgot to mention. I have switched to scala-logging. There is no cost of execution for debug statements unless debug is true.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.