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)