incorporate review feedback
- tons of documentation added - lift extraction of logClass into LogSource type-class - prefer Props.empty
This commit is contained in:
parent
7d0e006547
commit
b01640fddb
9 changed files with 260 additions and 147 deletions
|
|
@ -33,7 +33,7 @@ trait DeathWatchSpec { this: AkkaSpec with ImplicitSender with DefaultTimeout
|
|||
}
|
||||
|
||||
"notify with one Terminated message when an Actor is stopped" in {
|
||||
val terminal = system.actorOf(Props(context ⇒ { case _ ⇒ }))
|
||||
val terminal = system.actorOf(Props.empty)
|
||||
startWatching(terminal) ! "hallo"
|
||||
expectMsg("hallo") // this ensures that the DaemonMsgWatch has been received before we send the PoisonPill
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ trait DeathWatchSpec { this: AkkaSpec with ImplicitSender with DefaultTimeout
|
|||
}
|
||||
|
||||
"notify with one Terminated message when an Actor is already dead" in {
|
||||
val terminal = system.actorOf(Props(context ⇒ { case _ ⇒ }))
|
||||
val terminal = system.actorOf(Props.empty)
|
||||
|
||||
terminal ! PoisonPill
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ trait DeathWatchSpec { this: AkkaSpec with ImplicitSender with DefaultTimeout
|
|||
}
|
||||
|
||||
"notify with all monitors with one Terminated message when an Actor is stopped" in {
|
||||
val terminal = system.actorOf(Props(context ⇒ { case _ ⇒ }))
|
||||
val terminal = system.actorOf(Props.empty)
|
||||
val monitor1, monitor2, monitor3 = startWatching(terminal)
|
||||
|
||||
terminal ! PoisonPill
|
||||
|
|
@ -67,7 +67,7 @@ trait DeathWatchSpec { this: AkkaSpec with ImplicitSender with DefaultTimeout
|
|||
}
|
||||
|
||||
"notify with _current_ monitors with one Terminated message when an Actor is stopped" in {
|
||||
val terminal = system.actorOf(Props(context ⇒ { case _ ⇒ }))
|
||||
val terminal = system.actorOf(Props.empty)
|
||||
val monitor1, monitor3 = startWatching(terminal)
|
||||
val monitor2 = system.actorOf(Props(new Actor {
|
||||
context.watch(terminal)
|
||||
|
|
|
|||
|
|
@ -208,8 +208,9 @@ object ActorModelSpec {
|
|||
await(deadline)(stats.restarts.get() == restarts)
|
||||
} catch {
|
||||
case e ⇒
|
||||
system.eventStream.publish(Error(e, Option(dispatcher).toString,
|
||||
if (dispatcher ne null) dispatcher.getClass else this.getClass,
|
||||
system.eventStream.publish(Error(e,
|
||||
Option(dispatcher).toString,
|
||||
(Option(dispatcher) getOrElse this).getClass,
|
||||
"actual: " + stats + ", required: InterceptorStats(susp=" + suspensions +
|
||||
",res=" + resumes + ",reg=" + registers + ",unreg=" + unregisters +
|
||||
",recv=" + msgsReceived + ",proc=" + msgsProcessed + ",restart=" + restarts))
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
|
|||
}
|
||||
val log = LoggingReceive("funky")(r)
|
||||
log.isDefinedAt("hallo")
|
||||
expectMsg(1 second, Logging.Debug("funky", classOf[String], "received unhandled message hallo"))
|
||||
expectMsg(1 second, Logging.Debug("funky", classOf[DummyClassForStringSources], "received unhandled message hallo"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,15 +168,85 @@ trait LoggingBus extends ActorEventBus {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* This trait defines the interface to be provided by a “log source formatting
|
||||
* rule” as used by [[akka.event.Logging]]’s `apply`/`create` method.
|
||||
*
|
||||
* See the companion object for default implementations.
|
||||
*
|
||||
* Example:
|
||||
* {{{
|
||||
* trait MyType { // as an example
|
||||
* def name: String
|
||||
* }
|
||||
*
|
||||
* implicit val myLogSourceType: LogSource[MyType] = new LogSource {
|
||||
* def genString(a: MyType) = a.name
|
||||
* }
|
||||
*
|
||||
* class MyClass extends MyType {
|
||||
* val log = Logging(eventStream, this) // will use "hallo" as logSource
|
||||
* def name = "hallo"
|
||||
* }
|
||||
* }}}
|
||||
*
|
||||
* The second variant is used for including the actor system’s address:
|
||||
* {{{
|
||||
* trait MyType { // as an example
|
||||
* def name: String
|
||||
* }
|
||||
*
|
||||
* implicit val myLogSourceType: LogSource[MyType] = new LogSource {
|
||||
* def genString(a: MyType) = a.name
|
||||
* def genString(a: MyType, s: ActorSystem) = a.name + "," + s
|
||||
* }
|
||||
*
|
||||
* class MyClass extends MyType {
|
||||
* val sys = ActorSyste("sys")
|
||||
* val log = Logging(sys, this) // will use "hallo,akka://sys" as logSource
|
||||
* def name = "hallo"
|
||||
* }
|
||||
* }}}
|
||||
*
|
||||
* The default implementation of the second variant will just call the first.
|
||||
*/
|
||||
trait LogSource[-T] {
|
||||
def genString(t: T): String
|
||||
def genString(t: T, system: ActorSystem): String = genString(t)
|
||||
def getClazz(t: T): Class[_] = t.getClass
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a “marker” class which is inserted as originator class into
|
||||
* [[akka.event.LogEvent]] when the string representation was supplied
|
||||
* directly.
|
||||
*/
|
||||
class DummyClassForStringSources
|
||||
|
||||
/**
|
||||
* This object holds predefined formatting rules for log sources.
|
||||
*
|
||||
* In case an [[akka.actor.ActorSystem]] is provided, the following apply:
|
||||
* <ul>
|
||||
* <li>[[akka.actor.Actor]] and [[akka.actor.ActorRef]] will be represented by their absolute physical path</li>
|
||||
* <li>providing a `String` as source will append "(<system address>)" and use the result</li>
|
||||
* <li>providing a `Class` will extract its simple name, append "(<system address>)" and use the result</li>
|
||||
* <li>anything else gives compile error unless implicit [[akka.event.LogSource]] is in scope for it</li>
|
||||
* </ul>
|
||||
*
|
||||
* In case a [[akka.event.LoggingBus]] is provided, the following apply:
|
||||
* <ul>
|
||||
* <li>[[akka.actor.Actor]] and [[akka.actor.ActorRef]] will be represented by their absolute physical path</li>
|
||||
* <li>providing a `String` as source will be used as is</li>
|
||||
* <li>providing a `Class` will extract its simple name</li>
|
||||
* <li>anything else gives compile error unless implicit [[akka.event.LogSource]] is in scope for it</li>
|
||||
* </ul>
|
||||
*/
|
||||
object LogSource {
|
||||
implicit val fromString: LogSource[String] = new LogSource[String] {
|
||||
def genString(s: String) = s
|
||||
override def genString(s: String, system: ActorSystem) = s + "(" + system + ")"
|
||||
override def getClazz(s: String) = classOf[DummyClassForStringSources]
|
||||
}
|
||||
|
||||
implicit val fromActor: LogSource[Actor] = new LogSource[Actor] {
|
||||
|
|
@ -191,29 +261,54 @@ object LogSource {
|
|||
val fromClass: LogSource[Class[_]] = new LogSource[Class[_]] {
|
||||
def genString(c: Class[_]) = simpleName(c)
|
||||
override def genString(c: Class[_], system: ActorSystem) = simpleName(c) + "(" + system + ")"
|
||||
override def getClazz(c: Class[_]) = c
|
||||
}
|
||||
implicit def fromAnyClass[T]: LogSource[Class[T]] = fromClass.asInstanceOf[LogSource[Class[T]]]
|
||||
|
||||
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 {
|
||||
case c: Class[_] ⇒ fromClass.genString(c)
|
||||
case a: Actor ⇒ fromActor.genString(a)
|
||||
case a: ActorRef ⇒ fromActorRef.genString(a)
|
||||
case s: String ⇒ s
|
||||
case x ⇒ simpleName(x)
|
||||
/**
|
||||
* Convenience converter access: given an implicit `LogSource`, generate the
|
||||
* string representation and originating class.
|
||||
*/
|
||||
def apply[T: LogSource](o: T): (String, Class[_]) = {
|
||||
val ls = implicitly[LogSource[T]]
|
||||
(ls.genString(o), ls.getClazz(o))
|
||||
}
|
||||
|
||||
def fromAnyRef(o: AnyRef, system: ActorSystem): String =
|
||||
/**
|
||||
* Convenience converter access: given an implicit `LogSource` and
|
||||
* [[akka.actor.ActorSystem]], generate the string representation and
|
||||
* originating class.
|
||||
*/
|
||||
def apply[T: LogSource](o: T, system: ActorSystem): (String, Class[_]) = {
|
||||
val ls = implicitly[LogSource[T]]
|
||||
(ls.genString(o, system), ls.getClazz(o))
|
||||
}
|
||||
|
||||
/**
|
||||
* construct string representation for any object according to
|
||||
* rules above with fallback to its `Class`’s simple name.
|
||||
*/
|
||||
def fromAnyRef(o: AnyRef): (String, Class[_]) =
|
||||
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 + ")"
|
||||
case c: Class[_] ⇒ apply(c)
|
||||
case a: Actor ⇒ apply(a)
|
||||
case a: ActorRef ⇒ apply(a)
|
||||
case s: String ⇒ apply(s)
|
||||
case x ⇒ (simpleName(x), x.getClass)
|
||||
}
|
||||
|
||||
/**
|
||||
* construct string representation for any object according to
|
||||
* rules above (including the actor system’s address) with fallback to its
|
||||
* `Class`’s simple name.
|
||||
*/
|
||||
def fromAnyRef(o: AnyRef, system: ActorSystem): (String, Class[_]) =
|
||||
o match {
|
||||
case c: Class[_] ⇒ apply(c)
|
||||
case a: Actor ⇒ apply(a)
|
||||
case a: ActorRef ⇒ apply(a)
|
||||
case s: String ⇒ apply(s)
|
||||
case x ⇒ (simpleName(x) + "(" + system + ")", x.getClass)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,140 +417,79 @@ object Logging {
|
|||
|
||||
/**
|
||||
* Obtain LoggingAdapter for the given actor system and source object. This
|
||||
* will use the system’s event stream.
|
||||
* will use the system’s event stream and include the system’s address in the
|
||||
* log source string.
|
||||
*
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li>if it is an Actor or ActorRef, its path is used</li>
|
||||
* <li>in case of a String it is used as is</li>
|
||||
* <li>in case of a class an approximation of its simpleName
|
||||
* <li>and in all other cases the simpleName of its class</li>
|
||||
* </ul>
|
||||
*
|
||||
* You can add your own rules quite easily:
|
||||
* <b>Do not use this if you want to supply a log category string (like
|
||||
* “com.example.app.whatever”) unaltered,</b> supply `system.eventStream` in this
|
||||
* case or use
|
||||
*
|
||||
* {{{
|
||||
* trait MyType { // as an example
|
||||
* def name: String
|
||||
* }
|
||||
*
|
||||
* implicit val myLogSourceType: LogSource[MyType] = new LogSource {
|
||||
* def genString(a: MyType) = a.name
|
||||
* }
|
||||
*
|
||||
* class MyClass extends MyType {
|
||||
* val log = Logging(eventStream, this) // will use "hallo" as logSource
|
||||
* def name = "hallo"
|
||||
* }
|
||||
* Logging(system, this.getClass)
|
||||
* }}}
|
||||
*
|
||||
* 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.
|
||||
* See the companion object of [[akka.event.LogSource]] for details.
|
||||
*
|
||||
* You can add your own rules quite easily, see [[akka.event.LogSource]].
|
||||
*/
|
||||
def apply[T: LogSource](system: ActorSystem, logSource: T): LoggingAdapter =
|
||||
new BusLogging(system.eventStream, LogSource(logSource, system), logSource.getClass)
|
||||
def apply[T: LogSource](system: ActorSystem, logSource: T): LoggingAdapter = {
|
||||
val (str, clazz) = LogSource(logSource, system)
|
||||
new BusLogging(system.eventStream, str, clazz)
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain LoggingAdapter for the given logging bus and source object.
|
||||
*
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li>if it is an Actor or ActorRef, its path is used</li>
|
||||
* <li>in case of a String it is used as is</li>
|
||||
* <li>in case of a class an approximation of its simpleName
|
||||
* <li>and in all other cases the simpleName of its class</li>
|
||||
* </ul>
|
||||
* 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.
|
||||
* See the companion object of [[akka.event.LogSource]] for details.
|
||||
*
|
||||
* You can add your own rules quite easily:
|
||||
*
|
||||
* {{{
|
||||
* trait MyType { // as an example
|
||||
* def name: String
|
||||
* }
|
||||
*
|
||||
* implicit val myLogSourceType: LogSource[MyType] = new LogSource {
|
||||
* def genString(a: MyType) = a.name
|
||||
* }
|
||||
*
|
||||
* class MyClass extends MyType {
|
||||
* val log = Logging(eventStream, this) // will use "hallo" as logSource
|
||||
* def name = "hallo"
|
||||
* }
|
||||
* }}}
|
||||
* You can add your own rules quite easily, see [[akka.event.LogSource]].
|
||||
*/
|
||||
def apply[T: LogSource](bus: LoggingBus, logSource: T): LoggingAdapter =
|
||||
new BusLogging(bus, implicitly[LogSource[T]].genString(logSource), logSource.getClass)
|
||||
def apply[T: LogSource](bus: LoggingBus, logSource: T): LoggingAdapter = {
|
||||
val (str, clazz) = LogSource(logSource)
|
||||
new BusLogging(bus, str, clazz)
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain LoggingAdapter for the given actor system and source object. This
|
||||
* will use the system’s event stream.
|
||||
* will use the system’s event stream and include the system’s address in the
|
||||
* log source string.
|
||||
*
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li>if it is an Actor or ActorRef, its path is used</li>
|
||||
* <li>in case of a String it is used as is</li>
|
||||
* <li>in case of a class an approximation of its simpleName
|
||||
* <li>and in all other cases the simpleName of its class</li>
|
||||
* </ul>
|
||||
*
|
||||
* You can add your own rules quite easily:
|
||||
* <b>Do not use this if you want to supply a log category string (like
|
||||
* “com.example.app.whatever”) unaltered,</b> supply `system.eventStream` in this
|
||||
* case or use
|
||||
*
|
||||
* {{{
|
||||
* trait MyType { // as an example
|
||||
* def name: String
|
||||
* }
|
||||
*
|
||||
* implicit val myLogSourceType: LogSource[MyType] = new LogSource {
|
||||
* def genString(a: MyType) = a.name
|
||||
* }
|
||||
*
|
||||
* class MyClass extends MyType {
|
||||
* val log = Logging(eventStream, this) // will use "hallo" as logSource
|
||||
* def name = "hallo"
|
||||
* }
|
||||
* Logging.getLogger(system, this.getClass());
|
||||
* }}}
|
||||
*
|
||||
* 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.
|
||||
* See the companion object of [[akka.event.LogSource]] for details.
|
||||
*/
|
||||
def getLogger(system: ActorSystem, logSource: AnyRef): LoggingAdapter = apply(system, LogSource.fromAnyRef(logSource, system))
|
||||
def getLogger(system: ActorSystem, logSource: AnyRef): LoggingAdapter = {
|
||||
val (str, clazz) = LogSource.fromAnyRef(logSource, system)
|
||||
new BusLogging(system.eventStream, str, clazz)
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain LoggingAdapter for the given logging bus and source object. This
|
||||
* will use the system’s event stream.
|
||||
* Obtain LoggingAdapter for the given logging bus and source object.
|
||||
*
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li>if it is an Actor or ActorRef, its path is used</li>
|
||||
* <li>in case of a String it is used as is</li>
|
||||
* <li>in case of a class an approximation of its simpleName
|
||||
* <li>and in all other cases the simpleName of its class</li>
|
||||
* </ul>
|
||||
*
|
||||
* You can add your own rules quite easily:
|
||||
*
|
||||
* {{{
|
||||
* trait MyType { // as an example
|
||||
* def name: String
|
||||
* }
|
||||
*
|
||||
* implicit val myLogSourceType: LogSource[MyType] = new LogSource {
|
||||
* def genString(a: MyType) = a.name
|
||||
* }
|
||||
*
|
||||
* class MyClass extends MyType {
|
||||
* val log = Logging(eventStream, this) // will use "hallo" as logSource
|
||||
* def name = "hallo"
|
||||
* }
|
||||
* }}}
|
||||
* 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.
|
||||
* See the companion object of [[akka.event.LogSource]] for details.
|
||||
*/
|
||||
//def getLogger(bus: LoggingBus, logSource: AnyRef): LoggingAdapter = apply(bus, LogSource.fromAnyRef(logSource))
|
||||
def getLogger(bus: LoggingBus, logSource: AnyRef): LoggingAdapter = {
|
||||
val (str, clazz) = LogSource.fromAnyRef(logSource)
|
||||
new BusLogging(bus, str, clazz)
|
||||
}
|
||||
|
||||
/**
|
||||
* Artificial exception injected into Error events if no Throwable is
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ object LoggingReceive {
|
|||
class LoggingReceive(source: AnyRef, r: Receive)(implicit system: ActorSystem) extends Receive {
|
||||
def isDefinedAt(o: Any) = {
|
||||
val handled = r.isDefinedAt(o)
|
||||
system.eventStream.publish(Debug(LogSource.fromAnyRef(source), source.getClass, "received " + (if (handled) "handled" else "unhandled") + " message " + o))
|
||||
val (str, clazz) = LogSource.fromAnyRef(source)
|
||||
system.eventStream.publish(Debug(str, clazz, "received " + (if (handled) "handled" else "unhandled") + " message " + o))
|
||||
handled
|
||||
}
|
||||
def apply(o: Any): Unit = r(o)
|
||||
|
|
|
|||
|
|
@ -17,8 +17,13 @@ as illustrated in this example:
|
|||
.. includecode:: code/akka/docs/event/LoggingDocTestBase.java
|
||||
:include: imports,my-actor
|
||||
|
||||
The second parameter to the ``Logging.getLogger`` is the source of this logging channel.
|
||||
The source object is translated to a String according to the following rules:
|
||||
The first parameter to ``Logging.getLogger`` could also be any
|
||||
:class:`LoggingBus`, specifically ``system.eventStream()``; in the demonstrated
|
||||
case, the actor system’s address is included in the ``akkaSource``
|
||||
representation of the log source (see `Logging Thread and Akka Source in MDC`_)
|
||||
while in the second case this is not automatically done. The second parameter
|
||||
to ``Logging.getLogger`` is the source of this logging channel. The source
|
||||
object is translated to a String according to the following rules:
|
||||
|
||||
* if it is an Actor or ActorRef, its path is used
|
||||
* in case of a String it is used as is
|
||||
|
|
@ -28,6 +33,13 @@ The source object is translated to a String according to the following rules:
|
|||
The log message may contain argument placeholders ``{}``, which will be substituted if the log level
|
||||
is enabled.
|
||||
|
||||
The Java :class:`Class` of the log source is also included in the generated
|
||||
:class:`LogEvent`. In case of a simple string this is replaced with a “marker”
|
||||
class :class:`akka.event.DummyClassForStringSources` in order to allow special
|
||||
treatment of this case, e.g. in the SLF4J event listener which will then use
|
||||
the string instead of the class’ name for looking up the logger instance to
|
||||
use.
|
||||
|
||||
Event Handler
|
||||
=============
|
||||
|
||||
|
|
@ -96,6 +108,12 @@ With Logback the thread name is available with ``%X{sourceThread}`` specifier wi
|
|||
</layout>
|
||||
</appender>
|
||||
|
||||
.. note::
|
||||
|
||||
It will probably be a good idea to use the ``sourceThread`` MDC value also in
|
||||
non-Akka parts of the application in order to have this property consistently
|
||||
available in the logs.
|
||||
|
||||
Another helpful facility is that Akka captures the actor’s address when
|
||||
instantiating a logger within it, meaning that the full instance identification
|
||||
is available for associating log messages e.g. with members of a router. This
|
||||
|
|
|
|||
|
|
@ -47,6 +47,24 @@ object LoggingDocSpec {
|
|||
}
|
||||
//#my-event-listener
|
||||
|
||||
//#my-source
|
||||
import akka.event.LogSource
|
||||
import akka.actor.ActorSystem
|
||||
|
||||
object MyType {
|
||||
implicit val logSource: LogSource[AnyRef] = new LogSource[AnyRef] {
|
||||
def genString(o: AnyRef): String = o.getClass.getName
|
||||
override def getClazz(o: AnyRef): Class[_] = o.getClass
|
||||
}
|
||||
}
|
||||
|
||||
class MyType(system: ActorSystem) {
|
||||
import MyType._
|
||||
import akka.event.Logging
|
||||
|
||||
val log = Logging(system, this)
|
||||
}
|
||||
//#my-source
|
||||
}
|
||||
|
||||
class LoggingDocSpec extends AkkaSpec {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ For convenience you can mixin the ``log`` member into actors, instead of definin
|
|||
.. code-block:: scala
|
||||
|
||||
class MyActor extends Actor with akka.actor.ActorLogging {
|
||||
...
|
||||
}
|
||||
|
||||
The second parameter to the ``Logging`` is the source of this logging channel.
|
||||
The source object is translated to a String according to the following rules:
|
||||
|
|
@ -29,17 +31,46 @@ The source object is translated to a String according to the following rules:
|
|||
* if it is an Actor or ActorRef, its path is used
|
||||
* in case of a String it is used as is
|
||||
* in case of a class an approximation of its simpleName
|
||||
* and in all other cases the simpleName of its class
|
||||
* and in all other cases a compile error occurs unless and implicit
|
||||
:class:`LogSource[T]` is in scope for the type in question.
|
||||
|
||||
The log message may contain argument placeholders ``{}``, which will be substituted if the log level
|
||||
is enabled.
|
||||
|
||||
Translating Log Source to String and Class
|
||||
------------------------------------------
|
||||
|
||||
The rules for translating the source object to the source string and class
|
||||
which are inserted into the :class:`LogEvent` during runtime are implemented
|
||||
using implicit parameters and thus fully customizable: simply create your own
|
||||
instance of :class:`LogSource[T]` and have it in scope when creating the
|
||||
logger.
|
||||
|
||||
.. includecode:: code/akka/docs/event/LoggingDocSpec.scala#my-source
|
||||
|
||||
This example creates a log source which mimics traditional usage of Java
|
||||
loggers, which are based upon the originating object’s class name as log
|
||||
category. The override of :meth:`getClazz` is only included for demonstration
|
||||
purposes as it contains exactly the default behavior.
|
||||
|
||||
.. note::
|
||||
|
||||
You may also create the string representation up front and pass that in as
|
||||
the log source, but be aware that then the :class:`Class[_]` which will be
|
||||
put in the :class:`LogEvent` is
|
||||
:class:`akka.event.DummyClassForStringSources`.
|
||||
|
||||
The SLF4J event listener treats this case specially (using the actual string
|
||||
to look up the logger instance to use instead of the class’ name), and you
|
||||
might want to do this also in case you implement your own loggin adapter.
|
||||
|
||||
Event Handler
|
||||
=============
|
||||
|
||||
Logging is performed asynchronously through an event bus. You can configure which event handlers that should
|
||||
subscribe to the logging events. That is done using the 'event-handlers' element in the :ref:`configuration`.
|
||||
Here you can also define the log level.
|
||||
Logging is performed asynchronously through an event bus. You can configure
|
||||
which event handlers that should subscribe to the logging events. That is done
|
||||
using the ``event-handlers`` element in the :ref:`configuration`. Here you can
|
||||
also define the log level.
|
||||
|
||||
.. code-block:: ruby
|
||||
|
||||
|
|
@ -50,7 +81,8 @@ Here you can also define the log level.
|
|||
loglevel = "DEBUG"
|
||||
}
|
||||
|
||||
The default one logs to STDOUT and is registered by default. It is not intended to be used for production. There is also an :ref:`slf4j-scala`
|
||||
The default one logs to STDOUT and is registered by default. It is not intended
|
||||
to be used for production. There is also an :ref:`slf4j-scala`
|
||||
event handler available in the 'akka-slf4j' module.
|
||||
|
||||
Example of creating a listener:
|
||||
|
|
@ -58,7 +90,6 @@ Example of creating a listener:
|
|||
.. includecode:: code/akka/docs/event/LoggingDocSpec.scala
|
||||
:include: my-event-listener
|
||||
|
||||
|
||||
.. _slf4j-scala:
|
||||
|
||||
SLF4J
|
||||
|
|
@ -98,6 +129,12 @@ With Logback the thread name is available with ``%X{sourceThread}`` specifier wi
|
|||
</layout>
|
||||
</appender>
|
||||
|
||||
.. note::
|
||||
|
||||
It will probably be a good idea to use the ``sourceThread`` MDC value also in
|
||||
non-Akka parts of the application in order to have this property consistently
|
||||
available in the logs.
|
||||
|
||||
Another helpful facility is that Akka captures the actor’s address when
|
||||
instantiating a logger within it, meaning that the full instance identification
|
||||
is available for associating log messages e.g. with members of a router. This
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import org.slf4j.{ Logger ⇒ SLFLogger, LoggerFactory ⇒ SLFLoggerFactory }
|
|||
import org.slf4j.MDC
|
||||
import akka.event.Logging._
|
||||
import akka.actor._
|
||||
import akka.event.DummyClassForStringSources
|
||||
|
||||
/**
|
||||
* Base trait for all classes that wants to be able use the SLF4J logging infrastructure.
|
||||
|
|
@ -19,7 +20,10 @@ trait SLF4JLogging {
|
|||
|
||||
object Logger {
|
||||
def apply(logger: String): SLFLogger = SLFLoggerFactory getLogger logger
|
||||
def apply(logClass: Class[_]): SLFLogger = SLFLoggerFactory getLogger logClass
|
||||
def apply(logClass: Class[_], logSource: String): SLFLogger = logClass match {
|
||||
case c if c == classOf[DummyClassForStringSources] ⇒ apply(logSource)
|
||||
case _ ⇒ SLFLoggerFactory getLogger logClass
|
||||
}
|
||||
def root: SLFLogger = apply(SLFLogger.ROOT_LOGGER_NAME)
|
||||
}
|
||||
|
||||
|
|
@ -39,24 +43,24 @@ class Slf4jEventHandler extends Actor with SLF4JLogging {
|
|||
case event @ Error(cause, logSource, logClass, message) ⇒
|
||||
withMdc(logSource, event.thread.getName) {
|
||||
cause match {
|
||||
case Error.NoCause ⇒ Logger(logClass).error(message.toString)
|
||||
case _ ⇒ Logger(logClass).error(message.toString, cause)
|
||||
case Error.NoCause ⇒ Logger(logClass, logSource).error(message.toString)
|
||||
case _ ⇒ Logger(logClass, logSource).error(message.toString, cause)
|
||||
}
|
||||
}
|
||||
|
||||
case event @ Warning(logSource, logClass, message) ⇒
|
||||
withMdc(logSource, event.thread.getName) {
|
||||
Logger(logClass).warn("{}", message.asInstanceOf[AnyRef])
|
||||
Logger(logClass, logSource).warn("{}", message.asInstanceOf[AnyRef])
|
||||
}
|
||||
|
||||
case event @ Info(logSource, logClass, message) ⇒
|
||||
withMdc(logSource, event.thread.getName) {
|
||||
Logger(logClass).info("{}", message.asInstanceOf[AnyRef])
|
||||
Logger(logClass, logSource).info("{}", message.asInstanceOf[AnyRef])
|
||||
}
|
||||
|
||||
case event @ Debug(logSource, logClass, message) ⇒
|
||||
withMdc(logSource, event.thread.getName) {
|
||||
Logger(logClass).debug("{}", message.asInstanceOf[AnyRef])
|
||||
Logger(logClass, logSource).debug("{}", message.asInstanceOf[AnyRef])
|
||||
}
|
||||
|
||||
case InitializeLogger(_) ⇒
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue