diff --git a/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala index c5ed765aab..67c94d3dd7 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala @@ -218,18 +218,19 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im } }) val name = fsm.path.toString + val fsmClass = fsm.underlyingActor.getClass system.eventStream.subscribe(testActor, classOf[Logging.Debug]) fsm ! "go" expectMsgPF(1 second, hint = "processing Event(go,null)") { - case Logging.Debug(`name`, _, s: String) if s.startsWith("processing Event(go,null) from Actor[") ⇒ true + case Logging.Debug(`name`, `fsmClass`, s: String) if s.startsWith("processing Event(go,null) from Actor[") ⇒ true } - expectMsg(1 second, Logging.Debug(name, fsm.underlyingActor.getClass, "setting timer 't'/1500 milliseconds: Shutdown")) - expectMsg(1 second, Logging.Debug(name, fsm.underlyingActor.getClass, "transition 1 -> 2")) + expectMsg(1 second, Logging.Debug(name, fsmClass, "setting timer 't'/1500 milliseconds: Shutdown")) + expectMsg(1 second, Logging.Debug(name, fsmClass, "transition 1 -> 2")) fsm ! "stop" expectMsgPF(1 second, hint = "processing Event(stop,null)") { - case Logging.Debug(`name`, _, s: String) if s.startsWith("processing Event(stop,null) from Actor[") ⇒ true + case Logging.Debug(`name`, `fsmClass`, s: String) if s.startsWith("processing Event(stop,null) from Actor[") ⇒ true } - expectMsgAllOf(1 second, Logging.Debug(name, fsm.underlyingActor.getClass, "canceling timer 't'"), Normal) + expectMsgAllOf(1 second, Logging.Debug(name, fsmClass, "canceling timer 't'"), Normal) expectNoMsg(1 second) system.eventStream.unsubscribe(testActor) } diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 8713df95b4..4681e88cfa 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -112,7 +112,7 @@ object Status { } trait ActorLogging { this: Actor ⇒ - val log = akka.event.Logging(context.system.eventStream, context.self) + val log = akka.event.Logging(context.system, context.self) } object Actor { diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index d940aa2c20..67a1603105 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -296,7 +296,7 @@ class LocalActorRefProvider( val nodename: String = "local" val clustername: String = "local" - val log = Logging(eventStream, "LocalActorRefProvider") + val log = Logging(eventStream, "LocalActorRefProvider(" + rootPath.address + ")") /* * generate name for temporary actor refs diff --git a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala index a4f1c2c37c..e24a3a29f2 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala @@ -330,7 +330,11 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor // this provides basic logging (to stdout) until .start() is called below val eventStream = new EventStream(DebugEventStream) eventStream.startStdoutLogger(settings) - val log = new BusLogging(eventStream, "ActorSystem", this.getClass) + + // unfortunately we need logging before we know the rootpath address, which wants to be inserted here + @volatile + private var _log = new BusLogging(eventStream, "ActorSystem(" + name + ")", this.getClass) + def log = _log val scheduler = createScheduler() @@ -383,6 +387,7 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor private lazy val _start: this.type = { // the provider is expected to start default loggers, LocalActorRefProvider does this provider.init(this) + _log = new BusLogging(eventStream, "ActorSystem(" + lookupRoot.path.address + ")", this.getClass) deadLetters.init(dispatcher, lookupRoot.path / "deadLetters") // this starts the reaper actor and the user-configured logging subscribers, which are also actors registerOnTermination(stopScheduler()) @@ -498,4 +503,6 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor } } + + override def toString = lookupRoot.path.root.address.toString } diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala index b49be8c0b5..eb573df767 100644 --- a/akka-actor/src/main/scala/akka/actor/FSM.scala +++ b/akka-actor/src/main/scala/akka/actor/FSM.scala @@ -190,7 +190,7 @@ trait FSM[S, D] extends Listeners { type Timeout = Option[Duration] type TransitionHandler = PartialFunction[(S, S), Unit] - val log = Logging(context.system, context.self) + val log = Logging(context.system, this) /** * **************************************** diff --git a/akka-actor/src/main/scala/akka/event/Logging.scala b/akka-actor/src/main/scala/akka/event/Logging.scala index 83bff79617..33c4b1339e 100644 --- a/akka-actor/src/main/scala/akka/event/Logging.scala +++ b/akka-actor/src/main/scala/akka/event/Logging.scala @@ -86,8 +86,9 @@ trait LoggingBus extends ActorEventBus { * Internal Akka use only */ private[akka] def startDefaultLoggers(system: ActorSystemImpl) { + val logName = simpleName(this) + "(" + system + ")" val level = levelFor(system.settings.LogLevel) getOrElse { - StandardOutLogger.print(Error(new EventHandlerException, simpleName(this), this.getClass, "unknown akka.stdout-loglevel " + system.settings.LogLevel)) + StandardOutLogger.print(Error(new EventHandlerException, logName, this.getClass, "unknown akka.stdout-loglevel " + system.settings.LogLevel)) ErrorLevel } try { @@ -101,7 +102,7 @@ trait LoggingBus extends ActorEventBus { } yield { try { ReflectiveAccess.getClassFor[Actor](loggerName) match { - case Right(actorClass) ⇒ addLogger(system, actorClass, level) + case Right(actorClass) ⇒ addLogger(system, actorClass, level, logName) case Left(exception) ⇒ throw exception } } catch { @@ -115,7 +116,7 @@ trait LoggingBus extends ActorEventBus { loggers = myloggers _logLevel = level } - publish(Debug(simpleName(this), this.getClass, "Default Loggers started")) + publish(Debug(logName, this.getClass, "Default Loggers started")) if (!(defaultLoggers contains StandardOutLoggerName)) { unsubscribe(StandardOutLogger) } @@ -150,18 +151,18 @@ trait LoggingBus extends ActorEventBus { publish(Debug(simpleName(this), this.getClass, "all default loggers stopped")) } - private def addLogger(system: ActorSystemImpl, clazz: Class[_ <: Actor], level: LogLevel): ActorRef = { + private def addLogger(system: ActorSystemImpl, clazz: Class[_ <: Actor], level: LogLevel, logName: String): ActorRef = { val name = "log" + Extension(system).id() + "-" + simpleName(clazz) val actor = system.systemActorOf(Props(clazz), name) implicit val timeout = Timeout(3 seconds) val response = try Await.result(actor ? InitializeLogger(this), timeout.duration) catch { case _: TimeoutException ⇒ - publish(Warning(simpleName(this), this.getClass, "Logger " + name + " did not respond within " + timeout + " to InitializeLogger(bus)")) + publish(Warning(logName, this.getClass, "Logger " + name + " did not respond within " + timeout + " to InitializeLogger(bus)")) } if (response != LoggerInitialized) throw new LoggerInitializationException("Logger " + name + " did not respond with LoggerInitialized, sent instead " + response) AllLogLevels filter (level >= _) foreach (l ⇒ subscribe(actor, classFor(l))) - publish(Debug(simpleName(this), this.getClass, "logger " + name + " started")) + publish(Debug(logName, this.getClass, "logger " + name + " started")) actor } @@ -169,11 +170,13 @@ trait LoggingBus extends ActorEventBus { trait LogSource[-T] { def genString(t: T): String + def genString(t: T, system: ActorSystem): String = genString(t) } object LogSource { implicit val fromString: LogSource[String] = new LogSource[String] { def genString(s: String) = s + override def genString(s: String, system: ActorSystem) = s + "(" + system + ")" } implicit val fromActor: LogSource[Actor] = new LogSource[Actor] { @@ -187,10 +190,13 @@ object LogSource { // this one unfortunately does not work as implicit, because existential types have some weird behavior val fromClass: LogSource[Class[_]] = new LogSource[Class[_]] { def genString(c: Class[_]) = simpleName(c) + override def genString(c: Class[_], system: ActorSystem) = simpleName(c) + "(" + system + ")" } implicit def fromAnyClass[T]: LogSource[Class[T]] = fromClass.asInstanceOf[LogSource[Class[T]]] - def apply[T: LogSource](o: T) = implicitly[LogSource[T]].genString(o) + def apply[T: LogSource](o: T): String = implicitly[LogSource[T]].genString(o) + + def apply[T: LogSource](o: T, system: ActorSystem): String = implicitly[LogSource[T]].genString(o, system) def fromAnyRef(o: AnyRef): String = o match { @@ -200,6 +206,15 @@ object LogSource { case s: String ⇒ s case x ⇒ simpleName(x) } + + def fromAnyRef(o: AnyRef, system: ActorSystem): String = + o match { + case c: Class[_] ⇒ fromClass.genString(c, system) + case a: Actor ⇒ fromActor.genString(a, system) + case a: ActorRef ⇒ fromActorRef.genString(a, system) + case s: String ⇒ fromString.genString(s, system) + case x ⇒ simpleName(x) + "(" + system + ")" + } } /** @@ -213,8 +228,8 @@ object LogSource { * ... * log.info("hello world!") * - * - * The source object is used in two fashions: its `Class[_]` will be part of + * + * The source object is used in two fashions: its `Class[_]` will be part of * all log events produced by this logger, plus a string representation is * generated which may contain per-instance information, see `apply` or `create` * below. @@ -305,6 +320,41 @@ object Logging { val infoFormat = "[INFO] [%s] [%s] [%s] %s".intern val debugFormat = "[DEBUG] [%s] [%s] [%s] %s".intern + /** + * Obtain LoggingAdapter for the given actor system and source object. This + * will use the system’s event stream. + * + * The source is used to identify the source of this logging channel and must have + * a corresponding implicit LogSource[T] instance in scope; by default these are + * provided for Class[_], Actor, ActorRef and String types. By these, the source + * object is translated to a String according to the following rules: + *