Merge pull request #1173 from akka/wip-2965-show-how-to-stop-stdout-logging-master-ban

Add new log level OFF. See #2965
This commit is contained in:
Björn Antonsson 2013-02-22 01:07:26 -08:00
commit e09f0ac3ff
10 changed files with 177 additions and 35 deletions

View file

@ -0,0 +1,96 @@
/**
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.event
import akka.testkit._
import scala.concurrent.duration._
import com.typesafe.config.{ Config, ConfigFactory }
import akka.actor.{ ActorRef, Actor, ActorSystem }
import org.scalatest.WordSpec
import org.scalatest.matchers.MustMatchers
import akka.event.Logging.{ LogEvent, LoggerInitialized, InitializeLogger }
object LoggerSpec {
val defaultConfig = ConfigFactory.parseString("""
akka {
stdout-loglevel = "WARNING"
loglevel = "DEBUG"
loggers = ["akka.event.LoggerSpec$TestLogger"]
}
""").withFallback(AkkaSpec.testConf)
val noLoggingConfig = ConfigFactory.parseString("""
akka {
stdout-loglevel = "OFF"
loglevel = "OFF"
loggers = ["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])
class LoggerSpec extends WordSpec with MustMatchers {
import LoggerSpec._
private def createSystemAndLogToBuffer(name: String, config: Config, shouldLog: Boolean) = {
val out = new java.io.ByteArrayOutputStream()
Console.withOut(out) {
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
}
"A normally configured actor system" must {
"log messages to standard output" in {
val out = createSystemAndLogToBuffer("defaultLogger", defaultConfig, true)
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, false)
out.size must be(0)
}
}
}

View file

@ -29,11 +29,11 @@ akka {
# Log level used by the configured loggers (see "loggers") as soon # Log level used by the configured loggers (see "loggers") as soon
# as they have been started; before that, see "stdout-loglevel" # as they have been started; before that, see "stdout-loglevel"
# Options: ERROR, WARNING, INFO, DEBUG # Options: OFF, ERROR, WARNING, INFO, DEBUG
loglevel = "INFO" loglevel = "INFO"
# Log level for the very basic logger activated during AkkaApplication startup # 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" stdout-loglevel = "WARNING"
# Log the complete configuration at INFO level when the actor system is started. # Log the complete configuration at INFO level when the actor system is started.

View file

@ -456,7 +456,7 @@ class LocalActorRefProvider private[akka] (
def stopWhenAllTerminationHooksDone(): Unit = def stopWhenAllTerminationHooksDone(): Unit =
if (terminationHooks.isEmpty) { if (terminationHooks.isEmpty) {
eventStream.stopDefaultLoggers() eventStream.stopDefaultLoggers(system)
context.stop(self) context.stop(self)
} }

View file

@ -67,19 +67,24 @@ trait LoggingBus extends ActorEventBus {
_logLevel = level _logLevel = level
} }
/** private def setUpStdoutLogger(config: Settings) {
* Internal Akka use only
*/
private[akka] def startStdoutLogger(config: Settings) {
val level = levelFor(config.StdoutLogLevel) getOrElse { 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)) StandardOutLogger.print(Error(new LoggerException, simpleName(this), this.getClass, "unknown akka.stdout-loglevel " + config.StdoutLogLevel))
ErrorLevel ErrorLevel
} }
AllLogLevels filter (level >= _) foreach (l subscribe(StandardOutLogger, classFor(l))) AllLogLevels filter (level >= _) foreach (l subscribe(StandardOutLogger, classFor(l)))
guard.withGuard { guard.withGuard {
loggers = Seq(StandardOutLogger) loggers :+= StandardOutLogger
_logLevel = level _logLevel = level
} }
}
/**
* Internal Akka use only
*/
private[akka] def startStdoutLogger(config: Settings) {
setUpStdoutLogger(config)
publish(Debug(simpleName(this), this.getClass, "StandardOutLogger started")) publish(Debug(simpleName(this), this.getClass, "StandardOutLogger started"))
} }
@ -89,7 +94,8 @@ trait LoggingBus extends ActorEventBus {
private[akka] def startDefaultLoggers(system: ActorSystemImpl) { private[akka] def startDefaultLoggers(system: ActorSystemImpl) {
val logName = simpleName(this) + "(" + system + ")" val logName = simpleName(this) + "(" + system + ")"
val level = levelFor(system.settings.LogLevel) getOrElse { 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 ErrorLevel
} }
try { try {
@ -99,7 +105,7 @@ trait LoggingBus extends ActorEventBus {
case loggers loggers case loggers loggers
} }
case 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 loggers
} }
val myloggers = val myloggers =
@ -145,10 +151,10 @@ trait LoggingBus extends ActorEventBus {
/** /**
* Internal Akka use only * Internal Akka use only
*/ */
private[akka] def stopDefaultLoggers() { private[akka] def stopDefaultLoggers(system: ActorSystem) {
val level = _logLevel // volatile access before reading loggers val level = _logLevel // volatile access before reading loggers
if (!(loggers contains StandardOutLogger)) { 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")) publish(Debug(simpleName(this), this.getClass, "shutting down: StandardOutLogger started"))
} }
for { for {
@ -173,7 +179,7 @@ trait LoggingBus extends ActorEventBus {
val actor = system.systemActorOf(Props(clazz), name) val actor = system.systemActorOf(Props(clazz), name)
implicit def timeout = implicit def timeout =
if (system.settings.EventHandlerStartTimeout.duration >= Duration.Zero) { 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]")) "[akka.event-handler-startup-timeout] config is deprecated, use [akka.logger-startup-timeout]"))
system.settings.EventHandlerStartTimeout system.settings.EventHandlerStartTimeout
} else system.settings.LoggerStartTimeout } else system.settings.LoggerStartTimeout
@ -424,16 +430,25 @@ object Logging {
final val InfoLevel = LogLevel(3) final val InfoLevel = LogLevel(3)
final val DebugLevel = LogLevel(4) 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, * Returns the LogLevel associated with the given string,
* valid inputs are upper or lowercase (not mixed) versions of: * valid inputs are upper or lowercase (not mixed) versions of:
* "error", "warning", "info" and "debug" * "error", "warning", "info" and "debug"
*/ */
def levelFor(s: String): Option[LogLevel] = s match { def levelFor(s: String): Option[LogLevel] = s.toLowerCase match {
case "ERROR" | "error" Some(ErrorLevel) case "off" Some(OffLevel)
case "WARNING" | "warning" Some(WarningLevel) case "error" Some(ErrorLevel)
case "INFO" | "info" Some(InfoLevel) case "warning" Some(WarningLevel)
case "DEBUG" | "debug" Some(DebugLevel) case "info" Some(InfoLevel)
case "debug" Some(DebugLevel)
case unknown None case unknown None
} }

View file

@ -95,12 +95,12 @@ A custom ``application.conf`` might look like this::
# Log level used by the configured loggers (see "loggers") as soon # Log level used by the configured loggers (see "loggers") as soon
# as they have been started; before that, see "stdout-loglevel" # as they have been started; before that, see "stdout-loglevel"
# Options: ERROR, WARNING, INFO, DEBUG # Options: OFF, ERROR, WARNING, INFO, DEBUG
loglevel = DEBUG loglevel = "DEBUG"
# Log level for the very basic logger activated during AkkaApplication startup # 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 stdout-loglevel = "DEBUG"
actor { actor {
default-dispatcher { 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:: differentiate actor systems within the hierarchy of the configuration::
myapp1 { myapp1 {
akka.loglevel = WARNING akka.loglevel = "WARNING"
my.own.setting = 43 my.own.setting = 43
} }
myapp2 { myapp2 {
akka.loglevel = ERROR akka.loglevel = "ERROR"
app2.setting = "appname" app2.setting = "appname"
} }
my.own.setting = 42 my.own.setting = 42
@ -245,15 +245,17 @@ system is this
.. code-block:: ruby .. code-block:: ruby
akka.loglevel = WARNING akka.loglevel = "WARNING"
my.own.setting = 43 my.own.setting = 43
my.other.setting = "hello" my.other.setting = "hello"
// plus myapp1 and myapp2 subtrees // plus myapp1 and myapp2 subtrees
while in the second one, only the “akka” subtree is lifted, with the following 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.own.setting = 42
my.other.setting = "hello" my.other.setting = "hello"
// plus myapp1 and myapp2 subtrees // plus myapp1 and myapp2 subtrees

View file

@ -56,7 +56,7 @@ You almost definitely need to have logging set to DEBUG to use any of the option
.. code-block:: ruby .. code-block:: ruby
akka { akka {
loglevel = DEBUG loglevel = "DEBUG"
} }
This config option is very good if you want to know what config settings are loaded by Akka: 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`. 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 Loggers
======= =======
@ -167,7 +181,7 @@ Here you can also define the log level.
# Loggers to register at boot time (akka.event.Logging$DefaultLogger logs # Loggers to register at boot time (akka.event.Logging$DefaultLogger logs
# to STDOUT) # to STDOUT)
loggers = ["akka.event.Logging$DefaultLogger"] loggers = ["akka.event.Logging$DefaultLogger"]
# Options: ERROR, WARNING, INFO, DEBUG # Options: OFF, ERROR, WARNING, INFO, DEBUG
loglevel = "DEBUG" loglevel = "DEBUG"
} }

View file

@ -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:: full logging of actor activities using this configuration fragment::
akka { akka {
loglevel = DEBUG loglevel = "DEBUG"
actor { actor {
debug { debug {
autoreceive = on autoreceive = on

View file

@ -23,7 +23,7 @@ object FaultHandlingDocSample extends App {
import Worker._ import Worker._
val config = ConfigFactory.parseString(""" val config = ConfigFactory.parseString("""
akka.loglevel = DEBUG akka.loglevel = "DEBUG"
akka.actor.debug { akka.actor.debug {
receive = on receive = on
lifecycle = on lifecycle = on

View file

@ -57,7 +57,7 @@ You almost definitely need to have logging set to DEBUG to use any of the option
.. code-block:: ruby .. code-block:: ruby
akka { akka {
loglevel = DEBUG loglevel = "DEBUG"
} }
This config option is very good if you want to know what config settings are loaded by Akka: 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 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. 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 Loggers
======= =======
@ -210,7 +225,7 @@ also define the log level.
# Loggers to register at boot time (akka.event.Logging$DefaultLogger logs # Loggers to register at boot time (akka.event.Logging$DefaultLogger logs
# to STDOUT) # to STDOUT)
loggers = ["akka.event.Logging$DefaultLogger"] loggers = ["akka.event.Logging$DefaultLogger"]
# Options: ERROR, WARNING, INFO, DEBUG # Options: OFF, ERROR, WARNING, INFO, DEBUG
loglevel = "DEBUG" loglevel = "DEBUG"
} }

View file

@ -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:: full logging of actor activities using this configuration fragment::
akka { akka {
loglevel = DEBUG loglevel = "DEBUG"
actor { actor {
debug { debug {
receive = on receive = on