1
votes

I have traits from two third party libraries that I'm trying to mix in to my own trait. They both define implicit vals named log.

However, they are of different types - one is an SLF4J Logger, the other is a Spray LoggingContext (which is really an Akka LoggingAdapter). In fact the second trait is from Spray, it's an HttpServer. (Not the most recent version you can find on Github which no longer has that val).

So, here's the code (library one renamed because it's proprietary, the Spray code snipped to show just relevant part):

object LibraryOneShim {
    trait LibraryOne {
        implicit val log: org.slf4j.Logger = ...
    }
}

// https://github.com/spray/spray/blob/a996a5b6bdd830e613583fed86e87bf049fdb8c0/spray-routing/src/main/scala/spray/routing/HttpService.scala
trait HttpService extends Directives {
    val log = LoggingContext.fromActorRefFactory // this is a LoggingContext/LoggingAdapter
}

trait MyTrait extends HttpService with LibraryOne {
    val myRoute = ...
}

class MyActor extends Actor with MyTrait {
    def receive = runRoute(myRoute)
}

This won't compile. The compiler complains:

error: overriding lazy value log in trait HttpService of type java.lang.Object with spray.util.LoggingContext; lazy value log in trait LibraryOne$class of type org.slf4j.Logger needs `override' modifier trait DemoService extends HttpService with LibraryOne {

Is there any way I can mix in these two traits together?

1

1 Answers

4
votes

As far as I can tell the only way is to create a CombinedLogger

class CombinedLogger(l1:Logger, l2:LoggingAdapter) extends Logger with LoggingAdapter {
   // proxy methods to the correct logger
}

If both loggers were declared as def you could use it like this:

override def log = new CombinedLogger(super[LibraryOne].log, super[HttpService].log)

In this case it's tricky because they are defined as val which tell the Scala compiler they are a single value that will not change. And because of that it will not allow you to call super.log. So you would need to copy the logic of the overridden traits.

The other tricky part in this case is that you would need to proxy 50+ methods in the CombinedLogger.