logger names for configuring akka logger using the

2020-07-10 08:29发布

问题:

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?

回答1:

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)"


回答2:

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")
  }
}