From a94749d57715a1059b59659ed139fdd97c209948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Antonsson?= Date: Tue, 19 Feb 2013 11:29:17 +0100 Subject: [PATCH 1/5] Add the LogLevel OFF that can be used to turn off logging. See #2965 Conflicts: akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala akka-docs/rst/java/logging.rst akka-docs/rst/scala/logging.rst --- .../test/scala/akka/event/LoggerSpec.scala | 62 +++++++++++++++++++ akka-actor/src/main/resources/reference.conf | 4 +- .../scala/akka/actor/ActorRefProvider.scala | 2 +- .../src/main/scala/akka/event/Logging.scala | 39 ++++++++---- akka-docs/rst/general/configuration.rst | 4 +- akka-docs/rst/java/logging.rst | 18 +++++- akka-docs/rst/scala/logging.rst | 19 +++++- 7 files changed, 126 insertions(+), 22 deletions(-) create mode 100644 akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala diff --git a/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala b/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala new file mode 100644 index 0000000000..2f97668b4c --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2009-2013 Typesafe Inc. + */ +package akka.event + +import akka.testkit.AkkaSpec +import com.typesafe.config.{ Config, ConfigFactory } +import org.scalatest.WordSpec +import akka.actor.ActorSystem +import org.scalatest.matchers.MustMatchers + +object LoggerSpec { + + val defaultConfig = ConfigFactory.parseString(""" + akka { + stdout-loglevel = WARNING + loglevel = DEBUG + } + """).withFallback(AkkaSpec.testConf) + + val noLoggingConfig = ConfigFactory.parseString(""" + akka { + stdout-loglevel = OFF + loglevel = OFF + } + """).withFallback(AkkaSpec.testConf) +} + +@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) +class LoggerSpec extends WordSpec with MustMatchers { + + import LoggerSpec._ + + private def createSystemAndLogToBuffer(name: String, config: Config) = { + val out = new java.io.ByteArrayOutputStream() + Console.withOut(out) { + val system = ActorSystem(name, config) + try { + system.log.error("Danger! Danger!") + } finally { + system.shutdown() + } + } + out + } + + "A normally configured actor system" must { + + "log messages to standard output" in { + val out = createSystemAndLogToBuffer("defaultLogger", defaultConfig) + out.size must be > (0) + } + } + + "An actor system configured with the logging turned off" must { + + "not log messages to standard output" in { + val out = createSystemAndLogToBuffer("noLogging", noLoggingConfig) + out.size must be(0) + } + } +} diff --git a/akka-actor/src/main/resources/reference.conf b/akka-actor/src/main/resources/reference.conf index 1eed4db675..bff860665e 100644 --- a/akka-actor/src/main/resources/reference.conf +++ b/akka-actor/src/main/resources/reference.conf @@ -29,11 +29,11 @@ akka { # Log level used by the configured loggers (see "loggers") as soon # as they have been started; before that, see "stdout-loglevel" - # Options: ERROR, WARNING, INFO, DEBUG + # Options: OFF, ERROR, WARNING, INFO, DEBUG loglevel = "INFO" # Log level for the very basic logger activated during AkkaApplication startup - # Options: ERROR, WARNING, INFO, DEBUG + # Options: OFF, ERROR, WARNING, INFO, DEBUG stdout-loglevel = "WARNING" # Log the complete configuration at INFO level when the actor system is started. diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index 7853832b87..5a9d7f65ba 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -455,7 +455,7 @@ class LocalActorRefProvider private[akka] ( def stopWhenAllTerminationHooksDone(): Unit = if (terminationHooks.isEmpty) { - eventStream.stopDefaultLoggers() + eventStream.stopDefaultLoggers(system) context.stop(self) } diff --git a/akka-actor/src/main/scala/akka/event/Logging.scala b/akka-actor/src/main/scala/akka/event/Logging.scala index 851c6cf1f3..9dd1dfd2c9 100644 --- a/akka-actor/src/main/scala/akka/event/Logging.scala +++ b/akka-actor/src/main/scala/akka/event/Logging.scala @@ -67,19 +67,23 @@ trait LoggingBus extends ActorEventBus { _logLevel = level } - /** - * Internal Akka use only - */ - private[akka] def startStdoutLogger(config: Settings) { + private def setUpStdoutLogger(config: Settings) { val level = levelFor(config.StdoutLogLevel) getOrElse { StandardOutLogger.print(Error(new LoggerException, simpleName(this), this.getClass, "unknown akka.stdout-loglevel " + config.StdoutLogLevel)) ErrorLevel } AllLogLevels filter (level >= _) foreach (l ⇒ subscribe(StandardOutLogger, classFor(l))) guard.withGuard { - loggers = Seq(StandardOutLogger) + loggers :+= StandardOutLogger _logLevel = level } + } + + /** + * Internal Akka use only + */ + private[akka] def startStdoutLogger(config: Settings) { + setUpStdoutLogger(config) publish(Debug(simpleName(this), this.getClass, "StandardOutLogger started")) } @@ -145,10 +149,10 @@ trait LoggingBus extends ActorEventBus { /** * Internal Akka use only */ - private[akka] def stopDefaultLoggers() { + private[akka] def stopDefaultLoggers(system: ActorSystem) { val level = _logLevel // volatile access before reading loggers if (!(loggers contains StandardOutLogger)) { - AllLogLevels filter (level >= _) foreach (l ⇒ subscribe(StandardOutLogger, classFor(l))) + setUpStdoutLogger(system.settings) publish(Debug(simpleName(this), this.getClass, "shutting down: StandardOutLogger started")) } for { @@ -424,17 +428,26 @@ object Logging { final val InfoLevel = LogLevel(3) final val DebugLevel = LogLevel(4) + /** + * Internal Akka use only + * + * Don't include the OffLevel in the AllLogLevels since we should never subscribe + * to some kind of OffEvent. + */ + private final val OffLevel = LogLevel(Int.MinValue) + /** * Returns the LogLevel associated with the given string, * valid inputs are upper or lowercase (not mixed) versions of: * "error", "warning", "info" and "debug" */ - def levelFor(s: String): Option[LogLevel] = s match { - case "ERROR" | "error" ⇒ Some(ErrorLevel) - case "WARNING" | "warning" ⇒ Some(WarningLevel) - case "INFO" | "info" ⇒ Some(InfoLevel) - case "DEBUG" | "debug" ⇒ Some(DebugLevel) - case unknown ⇒ None + def levelFor(s: String): Option[LogLevel] = s.toLowerCase match { + case "off" ⇒ Some(OffLevel) + case "error" ⇒ Some(ErrorLevel) + case "warning" ⇒ Some(WarningLevel) + case "info" ⇒ Some(InfoLevel) + case "debug" ⇒ Some(DebugLevel) + case unknown ⇒ None } /** diff --git a/akka-docs/rst/general/configuration.rst b/akka-docs/rst/general/configuration.rst index 94054ac007..e55c9add85 100644 --- a/akka-docs/rst/general/configuration.rst +++ b/akka-docs/rst/general/configuration.rst @@ -95,11 +95,11 @@ A custom ``application.conf`` might look like this:: # Log level used by the configured loggers (see "loggers") as soon # as they have been started; before that, see "stdout-loglevel" - # Options: ERROR, WARNING, INFO, DEBUG + # Options: OFF, ERROR, WARNING, INFO, DEBUG loglevel = DEBUG # Log level for the very basic logger activated during AkkaApplication startup - # Options: ERROR, WARNING, INFO, DEBUG + # Options: OFF, ERROR, WARNING, INFO, DEBUG stdout-loglevel = DEBUG actor { diff --git a/akka-docs/rst/java/logging.rst b/akka-docs/rst/java/logging.rst index e75aff0e55..73bd2825eb 100644 --- a/akka-docs/rst/java/logging.rst +++ b/akka-docs/rst/java/logging.rst @@ -56,7 +56,7 @@ You almost definitely need to have logging set to DEBUG to use any of the option .. code-block:: ruby akka { - loglevel = DEBUG + loglevel = "DEBUG" } This config option is very good if you want to know what config settings are loaded by Akka: @@ -153,6 +153,20 @@ If you want to see all messages that are received through remoting at DEBUG log Also see the logging options for TestKit: :ref:`actor.logging-java`. +Turn Off Logging +---------------- + +To turn off logging you can configure the log levels to be ``OFF`` like this. + +.. code-block:: ruby + + akka { + stdout-loglevel = "OFF" + loglevel = "OFF" + } + +The ``stdout-loglevel`` is only in effect during system startup and shutdown, and setting +it to ``OFF`` as well, ensures that nothing gets logged during system startup or shutdown. Loggers ======= @@ -167,7 +181,7 @@ Here you can also define the log level. # Loggers to register at boot time (akka.event.Logging$DefaultLogger logs # to STDOUT) loggers = ["akka.event.Logging$DefaultLogger"] - # Options: ERROR, WARNING, INFO, DEBUG + # Options: OFF, ERROR, WARNING, INFO, DEBUG loglevel = "DEBUG" } diff --git a/akka-docs/rst/scala/logging.rst b/akka-docs/rst/scala/logging.rst index 130569aa4c..f004770f5c 100644 --- a/akka-docs/rst/scala/logging.rst +++ b/akka-docs/rst/scala/logging.rst @@ -57,7 +57,7 @@ You almost definitely need to have logging set to DEBUG to use any of the option .. code-block:: ruby akka { - loglevel = DEBUG + loglevel = "DEBUG" } This config option is very good if you want to know what config settings are loaded by Akka: @@ -196,6 +196,21 @@ purposes as it contains exactly the default behavior. 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 logging adapter. +Turn Off Logging +---------------- + +To turn off logging you can configure the log levels to be ``OFF`` like this. + +.. code-block:: ruby + + akka { + stdout-loglevel = "OFF" + loglevel = "OFF" + } + +The ``stdout-loglevel`` is only in effect during system startup and shutdown, and setting +it to ``OFF`` as well, ensures that nothing gets logged during system startup or shutdown. + Loggers ======= @@ -210,7 +225,7 @@ also define the log level. # Loggers to register at boot time (akka.event.Logging$DefaultLogger logs # to STDOUT) loggers = ["akka.event.Logging$DefaultLogger"] - # Options: ERROR, WARNING, INFO, DEBUG + # Options: OFF, ERROR, WARNING, INFO, DEBUG loglevel = "DEBUG" } From ba957c8356c665ae796d82f1077d30be5fa4881a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Antonsson?= Date: Wed, 20 Feb 2013 10:07:45 +0100 Subject: [PATCH 2/5] Change documentation to consistently use quotes for log levels. See #2965 --- .../src/test/scala/akka/event/LoggerSpec.scala | 8 ++++---- akka-docs/rst/general/configuration.rst | 16 +++++++++------- akka-docs/rst/java/testing.rst | 2 +- .../code/docs/actor/FaultHandlingDocSample.scala | 2 +- akka-docs/rst/scala/testing.rst | 2 +- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala b/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala index 2f97668b4c..cb8d45a44f 100644 --- a/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala @@ -13,15 +13,15 @@ object LoggerSpec { val defaultConfig = ConfigFactory.parseString(""" akka { - stdout-loglevel = WARNING - loglevel = DEBUG + stdout-loglevel = "WARNING" + loglevel = "DEBUG" } """).withFallback(AkkaSpec.testConf) val noLoggingConfig = ConfigFactory.parseString(""" akka { - stdout-loglevel = OFF - loglevel = OFF + stdout-loglevel = "OFF" + loglevel = "OFF" } """).withFallback(AkkaSpec.testConf) } diff --git a/akka-docs/rst/general/configuration.rst b/akka-docs/rst/general/configuration.rst index e55c9add85..d5feabe4d2 100644 --- a/akka-docs/rst/general/configuration.rst +++ b/akka-docs/rst/general/configuration.rst @@ -96,11 +96,11 @@ A custom ``application.conf`` might look like this:: # Log level used by the configured loggers (see "loggers") as soon # as they have been started; before that, see "stdout-loglevel" # Options: OFF, ERROR, WARNING, INFO, DEBUG - loglevel = DEBUG + loglevel = "DEBUG" # Log level for the very basic logger activated during AkkaApplication startup # Options: OFF, ERROR, WARNING, INFO, DEBUG - stdout-loglevel = DEBUG + stdout-loglevel = "DEBUG" actor { default-dispatcher { @@ -222,11 +222,11 @@ from the whole class path, it is easiest to utilize that functionality and differentiate actor systems within the hierarchy of the configuration:: myapp1 { - akka.loglevel = WARNING + akka.loglevel = "WARNING" my.own.setting = 43 } myapp2 { - akka.loglevel = ERROR + akka.loglevel = "ERROR" app2.setting = "appname" } my.own.setting = 42 @@ -245,15 +245,17 @@ system is this .. code-block:: ruby - akka.loglevel = WARNING + akka.loglevel = "WARNING" my.own.setting = 43 my.other.setting = "hello" // plus myapp1 and myapp2 subtrees while in the second one, only the “akka” subtree is lifted, with the following -result:: +result - akka.loglevel = ERROR +.. code-block:: ruby + + akka.loglevel = "ERROR" my.own.setting = 42 my.other.setting = "hello" // plus myapp1 and myapp2 subtrees diff --git a/akka-docs/rst/java/testing.rst b/akka-docs/rst/java/testing.rst index b0828c41d9..0f8311821a 100644 --- a/akka-docs/rst/java/testing.rst +++ b/akka-docs/rst/java/testing.rst @@ -618,7 +618,7 @@ All these messages are logged at ``DEBUG`` level. To summarize, you can enable full logging of actor activities using this configuration fragment:: akka { - loglevel = DEBUG + loglevel = "DEBUG" actor { debug { autoreceive = on diff --git a/akka-docs/rst/scala/code/docs/actor/FaultHandlingDocSample.scala b/akka-docs/rst/scala/code/docs/actor/FaultHandlingDocSample.scala index 5be1f9a542..fd54bbcf53 100644 --- a/akka-docs/rst/scala/code/docs/actor/FaultHandlingDocSample.scala +++ b/akka-docs/rst/scala/code/docs/actor/FaultHandlingDocSample.scala @@ -23,7 +23,7 @@ object FaultHandlingDocSample extends App { import Worker._ val config = ConfigFactory.parseString(""" - akka.loglevel = DEBUG + akka.loglevel = "DEBUG" akka.actor.debug { receive = on lifecycle = on diff --git a/akka-docs/rst/scala/testing.rst b/akka-docs/rst/scala/testing.rst index ac6a63423d..0de33fc35c 100644 --- a/akka-docs/rst/scala/testing.rst +++ b/akka-docs/rst/scala/testing.rst @@ -698,7 +698,7 @@ All these messages are logged at ``DEBUG`` level. To summarize, you can enable full logging of actor activities using this configuration fragment:: akka { - loglevel = DEBUG + loglevel = "DEBUG" actor { debug { receive = on From 70d2f2a58f5fc1087d3c42b854157f6e126aa1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Antonsson?= Date: Wed, 20 Feb 2013 14:36:49 +0100 Subject: [PATCH 3/5] Ensure that logging propagates since it is asynchronous. See #3069 --- .../test/scala/akka/event/LoggerSpec.scala | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala b/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala index cb8d45a44f..762925be7a 100644 --- a/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala @@ -3,11 +3,13 @@ */ package akka.event -import akka.testkit.AkkaSpec +import akka.testkit._ +import scala.concurrent.duration._ import com.typesafe.config.{ Config, ConfigFactory } +import akka.actor.{ ActorRef, Actor, ActorSystem } import org.scalatest.WordSpec -import akka.actor.ActorSystem import org.scalatest.matchers.MustMatchers +import akka.event.Logging.{ LogEvent, LoggerInitialized, InitializeLogger } object LoggerSpec { @@ -15,6 +17,7 @@ object LoggerSpec { akka { stdout-loglevel = "WARNING" loglevel = "DEBUG" + event-handlers = ["akka.event.LoggerSpec$TestLogger"] } """).withFallback(AkkaSpec.testConf) @@ -22,8 +25,26 @@ object LoggerSpec { akka { stdout-loglevel = "OFF" loglevel = "OFF" + event-handlers = ["akka.event.LoggerSpec$TestLogger"] } """).withFallback(AkkaSpec.testConf) + + case class SetTarget(ref: ActorRef) + + class TestLogger extends Actor with Logging.StdOutLogger { + var target: Option[ActorRef] = None + override def receive: Receive = { + case InitializeLogger(bus) ⇒ + bus.subscribe(context.self, classOf[SetTarget]) + sender ! LoggerInitialized + case SetTarget(ref) ⇒ + target = Some(ref) + ref ! ("OK") + case event: LogEvent ⇒ + print(event) + target foreach { _ ! event.message } + } + } } @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) @@ -31,14 +52,27 @@ class LoggerSpec extends WordSpec with MustMatchers { import LoggerSpec._ - private def createSystemAndLogToBuffer(name: String, config: Config) = { + private def createSystemAndLogToBuffer(name: String, config: Config, shouldLog: Boolean) = { val out = new java.io.ByteArrayOutputStream() Console.withOut(out) { - val system = ActorSystem(name, config) + implicit val system = ActorSystem(name, config) try { + val probe = TestProbe() + system.eventStream.publish(SetTarget(probe.ref)) + probe.expectMsg("OK") system.log.error("Danger! Danger!") + // since logging is asynchronous ensure that it propagates + if (shouldLog) { + probe.fishForMessage(0.5.seconds.dilated) { + case "Danger! Danger!" ⇒ true + case _ ⇒ false + } + } else { + probe.expectNoMsg(0.5.seconds.dilated) + } } finally { system.shutdown() + system.awaitTermination(5.seconds.dilated) } } out @@ -47,7 +81,7 @@ class LoggerSpec extends WordSpec with MustMatchers { "A normally configured actor system" must { "log messages to standard output" in { - val out = createSystemAndLogToBuffer("defaultLogger", defaultConfig) + val out = createSystemAndLogToBuffer("defaultLogger", defaultConfig, true) out.size must be > (0) } } @@ -55,7 +89,7 @@ class LoggerSpec extends WordSpec with MustMatchers { "An actor system configured with the logging turned off" must { "not log messages to standard output" in { - val out = createSystemAndLogToBuffer("noLogging", noLoggingConfig) + val out = createSystemAndLogToBuffer("noLogging", noLoggingConfig, false) out.size must be(0) } } From c80d6a3cddd735e8cf38eabef9cc45c12f57790d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Antonsson?= Date: Thu, 21 Feb 2013 15:38:03 +0100 Subject: [PATCH 4/5] Change event-handlers to loggers. See #2965 --- akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala b/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala index 762925be7a..f4b6bf5dd9 100644 --- a/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/event/LoggerSpec.scala @@ -17,7 +17,7 @@ object LoggerSpec { akka { stdout-loglevel = "WARNING" loglevel = "DEBUG" - event-handlers = ["akka.event.LoggerSpec$TestLogger"] + loggers = ["akka.event.LoggerSpec$TestLogger"] } """).withFallback(AkkaSpec.testConf) @@ -25,7 +25,7 @@ object LoggerSpec { akka { stdout-loglevel = "OFF" loglevel = "OFF" - event-handlers = ["akka.event.LoggerSpec$TestLogger"] + loggers = ["akka.event.LoggerSpec$TestLogger"] } """).withFallback(AkkaSpec.testConf) From f6d076aba03a1a4293a00de197c89e658ab6c7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Antonsson?= Date: Fri, 22 Feb 2013 08:35:24 +0100 Subject: [PATCH 5/5] Only log log initializaton errors directly to StandardOutLogger. See #3069 --- akka-actor/src/main/scala/akka/event/Logging.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/akka-actor/src/main/scala/akka/event/Logging.scala b/akka-actor/src/main/scala/akka/event/Logging.scala index 9dd1dfd2c9..8d6b2494ec 100644 --- a/akka-actor/src/main/scala/akka/event/Logging.scala +++ b/akka-actor/src/main/scala/akka/event/Logging.scala @@ -69,6 +69,7 @@ trait LoggingBus extends ActorEventBus { private def setUpStdoutLogger(config: Settings) { val level = levelFor(config.StdoutLogLevel) getOrElse { + // only log initialization errors directly with StandardOutLogger.print StandardOutLogger.print(Error(new LoggerException, simpleName(this), this.getClass, "unknown akka.stdout-loglevel " + config.StdoutLogLevel)) ErrorLevel } @@ -93,7 +94,8 @@ trait LoggingBus extends ActorEventBus { private[akka] def startDefaultLoggers(system: ActorSystemImpl) { val logName = simpleName(this) + "(" + system + ")" val level = levelFor(system.settings.LogLevel) getOrElse { - StandardOutLogger.print(Error(new LoggerException, logName, this.getClass, "unknown akka.stdout-loglevel " + system.settings.LogLevel)) + // only log initialization errors directly with StandardOutLogger.print + StandardOutLogger.print(Error(new LoggerException, logName, this.getClass, "unknown akka.loglevel " + system.settings.LogLevel)) ErrorLevel } try { @@ -103,7 +105,7 @@ trait LoggingBus extends ActorEventBus { case loggers ⇒ loggers } case loggers ⇒ - StandardOutLogger.print(Warning(logName, this.getClass, "[akka.event-handlers] config is deprecated, use [akka.loggers]")) + publish(Warning(logName, this.getClass, "[akka.event-handlers] config is deprecated, use [akka.loggers]")) loggers } val myloggers = @@ -177,7 +179,7 @@ trait LoggingBus extends ActorEventBus { val actor = system.systemActorOf(Props(clazz), name) implicit def timeout = if (system.settings.EventHandlerStartTimeout.duration >= Duration.Zero) { - StandardOutLogger.print(Warning(logName, this.getClass, + publish(Warning(logName, this.getClass, "[akka.event-handler-startup-timeout] config is deprecated, use [akka.logger-startup-timeout]")) system.settings.EventHandlerStartTimeout } else system.settings.LoggerStartTimeout