diff --git a/akka-docs/java/logging.rst b/akka-docs/java/logging.rst
index 398a940468..01dedee0ad 100644
--- a/akka-docs/java/logging.rst
+++ b/akka-docs/java/logging.rst
@@ -218,9 +218,9 @@ Mapped Diagnostic Context (MDC) with attribute name ``sourceThread``.
With Logback the thread name is available with ``%X{sourceThread}`` specifier within the pattern layout configuration::
-
+
%date{ISO8601} %-5level %logger{36} %X{sourceThread} - %msg%n
-
+
.. note::
@@ -235,9 +235,9 @@ is available for associating log messages e.g. with members of a router. This
information is available in the MDC with attribute name ``akkaSource``::
-
+
%date{ISO8601} %-5level %logger{36} %X{akkaSource} - %msg%n
-
+
For more details on what this attribute contains—also for non-actors—please see
diff --git a/akka-docs/scala/logging.rst b/akka-docs/scala/logging.rst
index dc87126c5b..19630cda18 100644
--- a/akka-docs/scala/logging.rst
+++ b/akka-docs/scala/logging.rst
@@ -251,9 +251,9 @@ Mapped Diagnostic Context (MDC) with attribute name ``sourceThread``.
With Logback the thread name is available with ``%X{sourceThread}`` specifier within the pattern layout configuration::
-
+
%date{ISO8601} %-5level %logger{36} %X{sourceThread} - %msg%n
-
+
.. note::
@@ -268,9 +268,9 @@ is available for associating log messages e.g. with members of a router. This
information is available in the MDC with attribute name ``akkaSource``::
-
+
%date{ISO8601} %-5level %logger{36} %X{akkaSource} - %msg%n
-
+
For more details on what this attribute contains—also for non-actors—please see
diff --git a/akka-sbt-plugin/sample/src/main/config/logback.xml b/akka-sbt-plugin/sample/src/main/config/logback.xml
index 019d298192..20d035b1d2 100644
--- a/akka-sbt-plugin/sample/src/main/config/logback.xml
+++ b/akka-sbt-plugin/sample/src/main/config/logback.xml
@@ -3,9 +3,9 @@
-
+
%date{ISO8601} %-5level %X{akkaSource} %X{sourceThread} - %msg%n
-
+
diff --git a/akka-slf4j/src/main/scala/akka/event/slf4j/SLF4J.scala b/akka-slf4j/src/main/scala/akka/event/slf4j/Slf4jEventHandler.scala
similarity index 100%
rename from akka-slf4j/src/main/scala/akka/event/slf4j/SLF4J.scala
rename to akka-slf4j/src/main/scala/akka/event/slf4j/Slf4jEventHandler.scala
diff --git a/akka-slf4j/src/test/resources/logback-test.xml b/akka-slf4j/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..96674387c5
--- /dev/null
+++ b/akka-slf4j/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ %date{ISO8601} %-5level %logger %X{akkaSource} %X{sourceThread} - %msg%n
+
+
+
+
+
+ %date{ISO8601} level=[%level] logger=[%logger] akkaSource=[%X{akkaSource}] sourceThread=[%X{sourceThread}] - msg=[%msg]%n----%n
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/akka-slf4j/src/test/scala/akka/event/slf4j/Slf4jEventHandlerSpec.scala b/akka-slf4j/src/test/scala/akka/event/slf4j/Slf4jEventHandlerSpec.scala
new file mode 100644
index 0000000000..17af919fcc
--- /dev/null
+++ b/akka-slf4j/src/test/scala/akka/event/slf4j/Slf4jEventHandlerSpec.scala
@@ -0,0 +1,127 @@
+/**
+ * Copyright (C) 2009-2012 Typesafe Inc.
+ */
+package akka.event.slf4j
+
+import akka.testkit.AkkaSpec
+import akka.actor.Actor
+import akka.actor.ActorLogging
+import akka.util.duration._
+import akka.event.Logging
+import akka.actor.Props
+import ch.qos.logback.core.OutputStreamAppender
+import java.io.StringWriter
+import java.io.ByteArrayOutputStream
+import org.scalatest.BeforeAndAfterEach
+
+object Slf4jEventHandlerSpec {
+
+ // This test depends on logback configuration in src/test/resources/logback-test.xml
+
+ val config = """
+ akka {
+ loglevel = INFO
+ event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
+ }
+ """
+
+ class LogProducer extends Actor with ActorLogging {
+ def receive = {
+ case e: Exception ⇒
+ log.error(e, e.getMessage)
+ case (s: String, x: Int, y: Int) ⇒
+ log.info(s, x, y)
+ }
+ }
+
+ class MyLogSource
+
+ val output = new ByteArrayOutputStream
+ def outputString: String = output.toString("UTF-8")
+
+ class TestAppender extends OutputStreamAppender {
+
+ override def start(): Unit = {
+ setOutputStream(output)
+ super.start()
+ }
+ }
+
+}
+
+@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
+class Slf4jEventHandlerSpec extends AkkaSpec(Slf4jEventHandlerSpec.config) with BeforeAndAfterEach {
+ import Slf4jEventHandlerSpec._
+
+ val producer = system.actorOf(Props[LogProducer], name = "logProducer")
+
+ override def beforeEach(): Unit = {
+ output.reset()
+ }
+
+ "Slf4jEventHandler" must {
+
+ "log error with stackTrace" in {
+ producer ! new RuntimeException("Simulated error")
+
+ awaitCond(outputString.contains("----"), 5 seconds)
+ val s = outputString
+ s must include("akkaSource=[akka://Slf4jEventHandlerSpec/user/logProducer]")
+ s must include("level=[ERROR]")
+ s must include("logger=[akka.event.slf4j.Slf4jEventHandlerSpec$LogProducer]")
+ s must include regex ("sourceThread=\\[ForkJoinPool-[1-9][0-9]*-worker-[1-9][0-9]*\\]")
+ s must include("msg=[Simulated error]")
+ s must include("java.lang.RuntimeException: Simulated error")
+ s must include("at akka.event.slf4j.Slf4jEventHandlerSpec")
+ }
+
+ "log info with parameters" in {
+ producer ! ("test x={} y={}", 3, 17)
+
+ awaitCond(outputString.contains("----"), 5 seconds)
+ val s = outputString
+ s must include("akkaSource=[akka://Slf4jEventHandlerSpec/user/logProducer]")
+ s must include("level=[INFO]")
+ s must include("logger=[akka.event.slf4j.Slf4jEventHandlerSpec$LogProducer]")
+ s must include regex ("sourceThread=\\[ForkJoinPool-[1-9][0-9]*-worker-[1-9][0-9]*\\]")
+ s must include("msg=[test x=3 y=17]")
+ }
+
+ "include system info in akkaSource when creating Logging with system" in {
+ val log = Logging(system, "akka.event.slf4j.Slf4jEventHandlerSpec.MyLogSource")
+ log.info("test")
+ awaitCond(outputString.contains("----"), 5 seconds)
+ val s = outputString
+ s must include("akkaSource=[akka.event.slf4j.Slf4jEventHandlerSpec.MyLogSource(akka://Slf4jEventHandlerSpec)]")
+ s must include("logger=[akka.event.slf4j.Slf4jEventHandlerSpec.MyLogSource(akka://Slf4jEventHandlerSpec)]")
+ }
+
+ "not include system info in akkaSource when creating Logging with system.eventStream" in {
+ val log = Logging(system.eventStream, "akka.event.slf4j.Slf4jEventHandlerSpec.MyLogSource")
+ log.info("test")
+ awaitCond(outputString.contains("----"), 5 seconds)
+ val s = outputString
+ s must include("akkaSource=[akka.event.slf4j.Slf4jEventHandlerSpec.MyLogSource]")
+ s must include("logger=[akka.event.slf4j.Slf4jEventHandlerSpec.MyLogSource]")
+ }
+
+ "use short class name and include system info in akkaSource when creating Logging with system and class" in {
+ val log = Logging(system, classOf[MyLogSource])
+ log.info("test")
+ awaitCond(outputString.contains("----"), 5 seconds)
+ val s = outputString
+ s must include("akkaSource=[Slf4jEventHandlerSpec$MyLogSource(akka://Slf4jEventHandlerSpec)]")
+ s must include("logger=[akka.event.slf4j.Slf4jEventHandlerSpec$MyLogSource]")
+ }
+
+ "use short class name in akkaSource when creating Logging with system.eventStream and class" in {
+ val log = Logging(system.eventStream, classOf[MyLogSource])
+ log.info("test")
+ awaitCond(outputString.contains("----"), 5 seconds)
+ val s = outputString
+ s must include("akkaSource=[Slf4jEventHandlerSpec$MyLogSource]")
+ s must include("logger=[akka.event.slf4j.Slf4jEventHandlerSpec$MyLogSource]")
+ }
+ }
+
+}
diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala
index f810da86a6..306aa38e8f 100644
--- a/project/AkkaBuild.scala
+++ b/project/AkkaBuild.scala
@@ -431,7 +431,7 @@ object Dependencies {
val cluster = Seq(Test.junit, Test.scalatest)
- val slf4j = Seq(slf4jApi)
+ val slf4j = Seq(slf4jApi, Test.logback)
val agent = Seq(scalaStm, Test.scalatest, Test.junit)