diff --git a/akka-actor/src/main/scala/akka/AkkaApplication.scala b/akka-actor/src/main/scala/akka/AkkaApplication.scala index a47a375e21..96cc0568be 100644 --- a/akka-actor/src/main/scala/akka/AkkaApplication.scala +++ b/akka-actor/src/main/scala/akka/AkkaApplication.scala @@ -168,7 +168,7 @@ class AkkaApplication(val name: String, val config: Configuration) extends Actor // this provides basic logging (to stdout) until .start() is called below val mainbus = new MainBus(DebugMainBus) mainbus.startStdoutLogger(AkkaConfig) - val log = new MainBusLogging(mainbus, this) + val log = new BusLogging(mainbus, this) // TODO correctly pull its config from the config val dispatcherFactory = new Dispatchers(this) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index f8f701c4d2..c5aaac83df 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -11,7 +11,7 @@ import akka.AkkaApplication import java.util.concurrent.ConcurrentHashMap import com.eaio.uuid.UUID import akka.AkkaException -import akka.event.{ ActorClassification, DeathWatch, MainBusLogging } +import akka.event.{ ActorClassification, DeathWatch, Logging } import akka.dispatch._ /** @@ -91,7 +91,7 @@ class ActorRefProviderException(message: String) extends AkkaException(message) class LocalActorRefProvider(val app: AkkaApplication) extends ActorRefProvider { val terminationFuture = new DefaultPromise[AkkaApplication.ExitStatus](Timeout.never)(app.dispatcher) - val log = new MainBusLogging(app.mainbus, this) + val log = Logging(app.mainbus, this) /** * Top-level anchor for the supervision hierarchy of this actor system. Will diff --git a/akka-actor/src/main/scala/akka/actor/Deployer.scala b/akka-actor/src/main/scala/akka/actor/Deployer.scala index fecdc801fa..5522d9c978 100644 --- a/akka-actor/src/main/scala/akka/actor/Deployer.scala +++ b/akka-actor/src/main/scala/akka/actor/Deployer.scala @@ -8,7 +8,7 @@ import collection.immutable.Seq import java.util.concurrent.ConcurrentHashMap -import akka.event.MainBusLogging +import akka.event.Logging import akka.actor.DeploymentConfig._ import akka.{ AkkaException, AkkaApplication } import akka.config.{ Configuration, ConfigurationException } @@ -34,7 +34,7 @@ trait ActorDeployer { class Deployer(val app: AkkaApplication) extends ActorDeployer { val deploymentConfig = new DeploymentConfig(app) - val log = new MainBusLogging(app.mainbus, this) + val log = Logging(app.mainbus, this) // val defaultAddress = Node(Config.nodename) diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala index dee625d92c..f2cea81c6d 100644 --- a/akka-actor/src/main/scala/akka/actor/FSM.scala +++ b/akka-actor/src/main/scala/akka/actor/FSM.scala @@ -4,7 +4,7 @@ package akka.actor import akka.util._ -import akka.event.MainBusLogging +import akka.event.Logging import scala.collection.mutable import java.util.concurrent.ScheduledFuture @@ -190,7 +190,7 @@ trait FSM[S, D] extends ListenerManagement { type Timeout = Option[Duration] type TransitionHandler = PartialFunction[(S, S), Unit] - val log = new MainBusLogging(app.mainbus, context.self) + val log = Logging(app.mainbus, context.self) /** * **************************************** diff --git a/akka-actor/src/main/scala/akka/event/EventHandler.scala b/akka-actor/src/main/scala/akka/event/EventHandler.scala deleted file mode 100644 index 7a4a5fe0ad..0000000000 --- a/akka-actor/src/main/scala/akka/event/EventHandler.scala +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (C) 2009-2011 Typesafe Inc. - */ - -package akka.event - -import akka.actor._ -import akka.dispatch.Dispatchers -import akka.config.ConfigurationException -import akka.util.{ ListenerManagement, ReflectiveAccess } -import akka.serialization._ -import akka.AkkaException -import akka.AkkaApplication - -/** - * Event handler. - *

- * Create, add and remove a listener: - *

- * val eventHandlerListener = Actor.actorOf(new Actor {
- *   self.dispatcher = EventHandler.EventHandlerDispatcher
- *
- *   def receive = {
- *     case EventHandler.Error(cause, instance, message) ⇒ ...
- *     case EventHandler.Warning(instance, message)      ⇒ ...
- *     case EventHandler.Info(instance, message)         ⇒ ...
- *     case EventHandler.Debug(instance, message)        ⇒ ...
- *     case genericEvent                                 ⇒ ...
- * }
- * })
- *
- * EventHandler.addListener(eventHandlerListener)
- * ...
- * EventHandler.removeListener(eventHandlerListener)
- * 
- *

- * However best is probably to register the listener in the 'akka.conf' - * configuration file. - *

- * Log an error event: - *

- * EventHandler.notify(EventHandler.Error(exception, this, message))
- * 
- * Or use the direct methods (better performance): - *
- * EventHandler.error(exception, this, message)
- * 
- * - * Shut down the EventHandler: - *
- * EventHandler.shutdown()
- * 
- * - * @author Jonas Bonér - */ diff --git a/akka-actor/src/main/scala/akka/event/Logging.scala b/akka-actor/src/main/scala/akka/event/Logging.scala index 82a4df5d00..c93c763244 100644 --- a/akka-actor/src/main/scala/akka/event/Logging.scala +++ b/akka-actor/src/main/scala/akka/event/Logging.scala @@ -28,15 +28,24 @@ trait LoggingBus extends ActorEventBus { @volatile private var _logLevel: LogLevel = _ + /** + * Query currently set log level. See object Logging for more information. + */ def logLevel = _logLevel + /** + * Change log level: default loggers (i.e. from configuration file) are + * subscribed/unsubscribed as necessary so that they listen to all levels + * which are at least as severe as the given one. See object Logging for + * more information. + */ def logLevel_=(level: LogLevel) { for { l ← AllLogLevels if l > _logLevel && l <= level; log ← loggers } subscribe(log, classFor(l)) for { l ← AllLogLevels if l <= _logLevel && l > level; log ← loggers } unsubscribe(log, classFor(l)) _logLevel = level } - def startStdoutLogger(config: AkkaConfig) { + private[akka] def startStdoutLogger(config: AkkaConfig) { val level = levelFor(config.StdoutLogLevel) getOrElse { StandardOutLogger.print(Error(new EventHandlerException, this, "unknown akka.stdout-loglevel " + config.StdoutLogLevel)) ErrorLevel @@ -47,7 +56,7 @@ trait LoggingBus extends ActorEventBus { publish(Info(this, "StandardOutLogger started")) } - def startDefaultLoggers(app: AkkaApplication, config: AkkaConfig) { + private[akka] def startDefaultLoggers(app: AkkaApplication, config: AkkaConfig) { val level = levelFor(config.LogLevel) getOrElse { StandardOutLogger.print(Error(new EventHandlerException, this, "unknown akka.stdout-loglevel " + config.LogLevel)) ErrorLevel @@ -59,7 +68,7 @@ trait LoggingBus extends ActorEventBus { } loggers = for { loggerName ← defaultLoggers - if loggerName != DefaultLoggerName + if loggerName != StandardOutLoggerName } yield { try { ReflectiveAccess.getClassFor[Actor](loggerName) match { @@ -74,7 +83,7 @@ trait LoggingBus extends ActorEventBus { } } publish(Info(this, "Default Loggers started")) - if (defaultLoggers contains DefaultLoggerName) { + if (defaultLoggers contains StandardOutLoggerName) { loggers :+= StandardOutLogger } else { unsubscribe(StandardOutLogger) @@ -88,7 +97,7 @@ trait LoggingBus extends ActorEventBus { } } - def stopDefaultLoggers() { + private[akka] def stopDefaultLoggers() { val level = _logLevel // volatile access before reading loggers if (!(loggers contains StandardOutLogger)) { AllLogLevels filter (level >= _) foreach (l ⇒ subscribe(StandardOutLogger, classFor(l))) @@ -111,6 +120,24 @@ trait LoggingBus extends ActorEventBus { } +/** + * Main entry point for Akka logging: log levels and message types (aka + * channels) defined for the main transport medium, the main event bus. The + * recommended use is to obtain an implementation of the Logging trait with + * suitable and efficient methods for generating log events: + * + *

+ * val log = Logging(<bus>, <source object>)
+ * ...
+ * log.info("hello world!")
+ * 
+ * + * Loggers are attached to the level-specific channels Error, + * Warning, Info and Debug as + * appropriate for the configured (or set) log level. If you want to implement + * your own, make sure to handle these four event types plus the InitializeLogger + * message which is sent before actually attaching it to the logging bus. + */ object Logging { trait LogLevelType @@ -143,6 +170,7 @@ object Logging { case DebugLevel ⇒ classOf[Debug] } + // these type ascriptions/casts are necessary to avoid CCEs during construction while retaining correct type val AllLogLevels = Seq(ErrorLevel: AnyRef, WarningLevel, InfoLevel, DebugLevel).asInstanceOf[Seq[LogLevel]] val errorFormat = "[ERROR] [%s] [%s] [%s] %s\n%s".intern @@ -151,8 +179,8 @@ object Logging { val debugFormat = "[DEBUG] [%s] [%s] [%s] %s".intern val genericFormat = "[GENERIC] [%s] [%s]".intern - def apply(app: AkkaApplication, instance: AnyRef): Logging = new MainBusLogging(app.mainbus, instance) - def apply(bus: MainBus, instance: AnyRef): Logging = new MainBusLogging(bus, instance) + def apply(app: AkkaApplication, instance: AnyRef): Logging = new BusLogging(app.mainbus, instance) + def apply(bus: LoggingBus, instance: AnyRef): Logging = new BusLogging(bus, instance) class EventHandlerException extends AkkaException @@ -181,6 +209,11 @@ object Logging { def level = DebugLevel } + /** + * Message which is sent to each default logger (i.e. from configuration file) + * after its creation but before attaching it to the logging bus. The logger + * actor should handle this message, e.g. to register for more channels. + */ case class InitializeLogger(bus: LoggingBus) trait StdOutLogger { @@ -240,13 +273,25 @@ object Logging { } } + /** + * Actor-less logging implementation for synchronous logging to standard + * output. This logger is always attached first in order to be able to log + * failures during application start-up, even before normal logging is + * started. Its log level can be configured by setting + * akka.stdout-loglevel in akka.conf. + */ class StandardOutLogger extends MinimalActorRef with StdOutLogger { override val toString = "StandardOutLogger" override def postMessageToMailbox(obj: Any, channel: UntypedChannel) { print(obj) } } val StandardOutLogger = new StandardOutLogger - val DefaultLoggerName = StandardOutLogger.getClass.getName + val StandardOutLoggerName = StandardOutLogger.getClass.getName + /** + * Actor wrapper around the standard output logger. If + * akka.event-handlers is not set, it defaults to just this + * logger. + */ class DefaultLogger extends Actor with StdOutLogger { def receive = { case InitializeLogger(_) ⇒ @@ -270,7 +315,22 @@ object Logging { /** * Logging wrapper to make nicer and optimize: provide template versions which - * evaluate .toString only if the log level is actually enabled. + * evaluate .toString only if the log level is actually enabled. Typically used + * by obtaining an implementation from the Logging object: + * + *
+ * val log = Logging(<bus>, <source object>)
+ * ...
+ * log.info("hello world!")
+ * 
+ * + * All log-level methods support simple interpolation templates with up to four + * arguments placed by using {} within the template (first string + * argument): + * + *
+ * log.error(exception, "Exception while processing {} in state {}", msg, state)
+ * 
*/ trait Logging { @@ -333,21 +393,21 @@ trait Logging { } -class MainBusLogging(val mainbus: MainBus, val loggingInstance: AnyRef) extends Logging { +class BusLogging(val bus: LoggingBus, val loggingInstance: AnyRef) extends Logging { import Logging._ - def isErrorEnabled = mainbus.logLevel >= ErrorLevel - def isWarningEnabled = mainbus.logLevel >= WarningLevel - def isInfoEnabled = mainbus.logLevel >= InfoLevel - def isDebugEnabled = mainbus.logLevel >= DebugLevel + def isErrorEnabled = bus.logLevel >= ErrorLevel + def isWarningEnabled = bus.logLevel >= WarningLevel + def isInfoEnabled = bus.logLevel >= InfoLevel + def isDebugEnabled = bus.logLevel >= DebugLevel - protected def notifyError(cause: Throwable, message: String) { mainbus.publish(Error(cause, loggingInstance, message)) } + protected def notifyError(cause: Throwable, message: String) { bus.publish(Error(cause, loggingInstance, message)) } - protected def notifyWarning(message: String) { mainbus.publish(Warning(loggingInstance, message)) } + protected def notifyWarning(message: String) { bus.publish(Warning(loggingInstance, message)) } - protected def notifyInfo(message: String) { mainbus.publish(Info(loggingInstance, message)) } + protected def notifyInfo(message: String) { bus.publish(Info(loggingInstance, message)) } - protected def notifyDebug(message: String) { mainbus.publish(Debug(loggingInstance, message)) } + protected def notifyDebug(message: String) { bus.publish(Debug(loggingInstance, message)) } } \ No newline at end of file diff --git a/akka-testkit/src/test/scala/akka/testkit/AkkaSpec.scala b/akka-testkit/src/test/scala/akka/testkit/AkkaSpec.scala index 4264427e0d..27874aa799 100644 --- a/akka-testkit/src/test/scala/akka/testkit/AkkaSpec.scala +++ b/akka-testkit/src/test/scala/akka/testkit/AkkaSpec.scala @@ -9,14 +9,14 @@ import org.scalatest.matchers.MustMatchers import akka.AkkaApplication import akka.actor.{ Actor, ActorRef, Props } import akka.dispatch.MessageDispatcher -import akka.event.{ Logging, MainBusLogging } +import akka.event.Logging import akka.util.duration._ import akka.dispatch.FutureTimeoutException abstract class AkkaSpec(_application: AkkaApplication = AkkaApplication()) extends TestKit(_application) with WordSpec with MustMatchers with BeforeAndAfterAll { - val log: Logging = new MainBusLogging(app.mainbus, this) + val log: Logging = Logging(app.mainbus, this) final override def beforeAll { atStartup()