So, I am using Slf4jEventHandler and logback-classic. How do I configure the log levels for different actors separately? [I am using Akka 2.0_M2]
I tried doing something like
<configuration debug="true" scan="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="akka://TradeService" level="DEBUG" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
but that did not help at all:
INFO akka://TradeService/user/realTimeReqListener - Declaring queue
INFO akka://TradeService/user/restReqListener - Declaring queue
INFO akka://TradeService/user/restReqListener - Starting listening to queue
As you can see I am only getting INFO level logging for the actors. What is the naming hierarchy for actor loggers?
I am guessing that you are using an Akka 2.0 milestone, and I am further guessing that you obtain your logger like this:
val log = Logging(context.system, this)
As documented, the default representation of an actor in terms of log category is its path. Unfortunately, logback is not prepared to deal with actor hierarchies, it is setup to deal with package names (i.e. dot-separated hierarchy), which is why your setting affects the wrong logger. There were some changes in this area in Akka master recently which will be part of milestone 3 (to be released real soon now), where the default log category would be obtained from the actual implementation class (as per LoggerFactory.getLogger(someClass)
). If you want to achieve the same thing on your older Akka version, use
val log = Logging(context.system, getClass.getName)
Note that this of course does NOT unify the actor name hierarchy magically with your package names, i.e. you will have to configure per actor class as is customary for traditional Java logging frameworks. If you want that, write your own conversion from actor path to dot-separated hierarchical name and pass the resulting string to the factory:
val log = Logging(context.system.eventStream, mangleMyName(self.path))
The change to using eventStream
instead of plain system
will be necessary once you update to a more recent version, because another change was that the system’s name will now be appended to plain logging categories if passing in a system. Assume system.name == "Fred"
:
val log = Logging(context.system, "testa") // will log as "testa(Fred)"
The Akka Logging doesn't integrate well with Play out of the box. It also uses a different API to slf4j e.g. warning instead of warn, making it harder to replace should you need to.
The trait below forces the classical slf4j/log4j package name structure making loggers easier to configure in the application.conf
import org.slf4j.LoggerFactory
import akka.actor.ActorRef
trait ActorLogger {
implicit val self:ActorRef
protected val log = LoggerFactory.getLogger(getClass().getName() + "_" + self.path.toString())
}
and use it like this
class Foo extends Actor with ActorLogger {
def run = {
log.info("hi")
log.warn("hi")
}
}