Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2009-2012 Typesafe Inc.
*/
package akka.event
import akka.actor._
import akka.AkkaException
import akka.actor.ActorSystem.Settings
import akka.config.ConfigurationException
import akka.util.ReentrantGuard
import akka.util.duration._
import akka.util.Timeout
import java.util.concurrent.atomic.AtomicInteger
import scala.util.control.NoStackTrace
import java.util.concurrent.TimeoutException
import akka.dispatch.Await
/**
* This trait brings log level handling to the EventStream: it reads the log
* levels for the initial logging (StandardOutLogger) and the loggers & level
* for after-init logging, possibly keeping the StandardOutLogger enabled if
* it is part of the configured loggers. All configured loggers are treated as
* system services and managed by this trait, i.e. subscribed/unsubscribed in
* response to changes of LoggingBus.logLevel.
*/
trait LoggingBus extends ActorEventBus {
type Event >: Logging.LogEvent
type Classifier >: Class[_]
import Logging._
private val guard = new ReentrantGuard
private var loggers = Seq.empty[ActorRef]
private var _logLevel: LogLevel = _
/**
* Query currently set log level. See object Logging for more information.
*/
def logLevel = guard.withGuard { _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.
*
* NOTE: if the StandardOutLogger is configured also as normal logger, it
* will not participate in the automatic management of log level
* subscriptions!
*/
def setLogLevel(level: LogLevel): Unit = guard.withGuard {
for {
l ← AllLogLevels
// subscribe if previously ignored and now requested
if l > _logLevel && l <= level
log ← loggers
} subscribe(log, classFor(l))
for {
l ← AllLogLevels
// unsubscribe if previously registered and now ignored
if l <= _logLevel && l > level
log ← loggers
} unsubscribe(log, classFor(l))
_logLevel = level
}
/**
* Internal Akka use only
*/
private[akka] def startStdoutLogger(config: Settings) {
val level = levelFor(config.StdoutLogLevel) getOrElse {
StandardOutLogger.print(Error(new EventHandlerException, 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)
_logLevel = level
}
publish(Debug(simpleName(this), this.getClass, "StandardOutLogger started"))
}
/**
* Internal Akka use only
*/
private[akka] def startDefaultLoggers(system: ActorSystemImpl) {
val logName = simpleName(this) + "(" + system + ")"
val level = levelFor(system.settings.LogLevel) getOrElse {
StandardOutLogger.print(Error(new EventHandlerException, logName, this.getClass, "unknown akka.stdout-loglevel " + system.settings.LogLevel))
ErrorLevel
}
try {
val defaultLoggers = system.settings.EventHandlers match {
case Nil ⇒ "akka.event.Logging$DefaultLogger" :: Nil
case loggers ⇒ loggers
}
val myloggers = for {
loggerName ← defaultLoggers
if loggerName != StandardOutLoggerName
} yield {
try {
system.dynamicAccess.getClassFor[Actor](loggerName) match {
case Right(actorClass) ⇒ addLogger(system, actorClass, level, logName)
case Left(exception) ⇒ throw exception
}
} catch {
case e: Exception ⇒
throw new ConfigurationException(
"Event Handler specified in config can't be loaded [" + loggerName +
"] due to [" + e.toString + "]", e)
}
}
guard.withGuard {
loggers = myloggers
_logLevel = level
}
publish(Debug(logName, this.getClass, "Default Loggers started"))
if (!(defaultLoggers contains StandardOutLoggerName)) {
unsubscribe(StandardOutLogger)
}
} catch {
case e: Exception ⇒
System.err.println("error while starting up EventHandler")
e.printStackTrace()
throw new ConfigurationException("Could not start Event Handler due to [" + e.toString + "]")
}
}
/**
* Internal Akka use only
*/
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)))
publish(Debug(simpleName(this), this.getClass, "shutting down: StandardOutLogger started"))
}
for {
logger ← loggers
if logger != StandardOutLogger
} {
// this is very necessary, else you get infinite loop with DeadLetter
unsubscribe(logger)
logger match {
case ref: InternalActorRef ⇒ ref.stop()
case _ ⇒
}
}
publish(Debug(simpleName(this), this.getClass, "all default loggers stopped"))
}
private def addLogger(system: ActorSystemImpl, clazz: Class[_ <: Actor], level: LogLevel, logName: String): ActorRef = {
val name = "log" + Extension(system).id() + "-" + simpleName(clazz)
val actor = system.systemActorOf(Props(clazz), name)
implicit val timeout = system.settings.EventHandlerStartTimeout
import akka.pattern.ask
val response = try Await.result(actor ? InitializeLogger(this), timeout.duration) catch {
case _: TimeoutException ⇒
publish(Warning(logName, this.getClass, "Logger " + name + " did not respond within " + timeout + " to InitializeLogger(bus)"))
"[TIMEOUT]"
}
if (response != LoggerInitialized)
throw new LoggerInitializationException("Logger " + name + " did not respond with LoggerInitialized, sent instead " + response)
AllLogLevels filter (level >= _) foreach (l ⇒ subscribe(actor, classFor(l)))
publish(Debug(logName, this.getClass, "logger " + name + " started"))
actor
}
}
/**
* This trait defines the interface to be provided by a “log source formatting
* rule” as used by [[akka.event.Logging]]’s `apply`/`create` method.
*
* See the companion object for default implementations.
*
* Example:
* {{{
* trait MyType { // as an example
* def name: String
* }
*
* implicit val myLogSourceType: LogSource[MyType] = new LogSource {
* def genString(a: MyType) = a.name
* }
*
* class MyClass extends MyType {
* val log = Logging(eventStream, this) // will use "hallo" as logSource
* def name = "hallo"
* }
* }}}
*
* The second variant is used for including the actor system’s address:
* {{{
* trait MyType { // as an example
* def name: String
* }
*
* implicit val myLogSourceType: LogSource[MyType] = new LogSource {
* def genString(a: MyType) = a.name
* def genString(a: MyType, s: ActorSystem) = a.name + "," + s
* }
*
* class MyClass extends MyType {
* val sys = ActorSyste("sys")
* val log = Logging(sys, this) // will use "hallo,akka://sys" as logSource
* def name = "hallo"
* }
* }}}
*
* The default implementation of the second variant will just call the first.
*/
trait LogSource[-T] {
def genString(t: T): String
def genString(t: T, system: ActorSystem): String = genString(t)
def getClazz(t: T): Class[_] = t.getClass
}
/**
* This is a “marker” class which is inserted as originator class into
* [[akka.event.LogEvent]] when the string representation was supplied
* directly.
*/
class DummyClassForStringSources
/**
* This object holds predefined formatting rules for log sources.
*
* In case an [[akka.actor.ActorSystem]] is provided, the following apply:
*
*
[[akka.actor.Actor]] and [[akka.actor.ActorRef]] will be represented by their absolute physical path
*
providing a `String` as source will append "()" and use the result
*
providing a `Class` will extract its simple name, append "()" and use the result
*
anything else gives compile error unless implicit [[akka.event.LogSource]] is in scope for it
*
*
* In case a [[akka.event.LoggingBus]] is provided, the following apply:
*
*
[[akka.actor.Actor]] and [[akka.actor.ActorRef]] will be represented by their absolute physical path
*
providing a `String` as source will be used as is
*
providing a `Class` will extract its simple name
*
anything else gives compile error unless implicit [[akka.event.LogSource]] is in scope for it
*
*/
object LogSource {
implicit val fromString: LogSource[String] = new LogSource[String] {
def genString(s: String) = s
override def genString(s: String, system: ActorSystem) = s + "(" + system + ")"
override def getClazz(s: String) = classOf[DummyClassForStringSources]
}
implicit val fromActor: LogSource[Actor] = new LogSource[Actor] {
def genString(a: Actor) = a.self.path.toString
}
implicit val fromActorRef: LogSource[ActorRef] = new LogSource[ActorRef] {
def genString(a: ActorRef) = a.path.toString
}
// this one unfortunately does not work as implicit, because existential types have some weird behavior
val fromClass: LogSource[Class[_]] = new LogSource[Class[_]] {
def genString(c: Class[_]) = simpleName(c)
override def genString(c: Class[_], system: ActorSystem) = simpleName(c) + "(" + system + ")"
override def getClazz(c: Class[_]) = c
}
implicit def fromAnyClass[T]: LogSource[Class[T]] = fromClass.asInstanceOf[LogSource[Class[T]]]
/**
* Convenience converter access: given an implicit `LogSource`, generate the
* string representation and originating class.
*/
def apply[T: LogSource](o: T): (String, Class[_]) = {
val ls = implicitly[LogSource[T]]
(ls.genString(o), ls.getClazz(o))
}
/**
* Convenience converter access: given an implicit `LogSource` and
* [[akka.actor.ActorSystem]], generate the string representation and
* originating class.
*/
def apply[T: LogSource](o: T, system: ActorSystem): (String, Class[_]) = {
val ls = implicitly[LogSource[T]]
(ls.genString(o, system), ls.getClazz(o))
}
/**
* construct string representation for any object according to
* rules above with fallback to its `Class`’s simple name.
*/
def fromAnyRef(o: AnyRef): (String, Class[_]) =
o match {
case c: Class[_] ⇒ apply(c)
case a: Actor ⇒ apply(a)
case a: ActorRef ⇒ apply(a)
case s: String ⇒ apply(s)
case x ⇒ (simpleName(x), x.getClass)
}
/**
* construct string representation for any object according to
* rules above (including the actor system’s address) with fallback to its
* `Class`’s simple name.
*/
def fromAnyRef(o: AnyRef, system: ActorSystem): (String, Class[_]) =
o match {
case c: Class[_] ⇒ apply(c)
case a: Actor ⇒ apply(a)
case a: ActorRef ⇒ apply(a)
case s: String ⇒ apply(s)
case x ⇒ (simpleName(x) + "(" + system + ")", x.getClass)
}
}
/**
* 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:
*
*
*
* The source object is used in two fashions: its `Class[_]` will be part of
* all log events produced by this logger, plus a string representation is
* generated which may contain per-instance information, see `apply` or `create`
* below.
*
* 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.
*
* Logging is configured in akka.conf by setting (some of) the following:
*
*
* akka {
* event-handlers = ["akka.slf4j.Slf4jEventHandler"] # for example
* loglevel = "INFO" # used when normal logging ("event-handlers") has been started
* stdout-loglevel = "WARN" # used during application start-up until normal logging is available
* }
*
*/
object Logging {
@deprecated("Will become private[akka] in 2.1, this is not user-api", "2.0.2")
object Extension extends ExtensionKey[LogExt]
@deprecated("Will become private[akka] in 2.1, this is not user-api", "2.0.2")
class LogExt(system: ExtendedActorSystem) extends Extension {
private val loggerId = new AtomicInteger
def id() = loggerId.incrementAndGet()
}
/**
* Marker trait for annotating LogLevel, which must be Int after erasure.
*/
trait LogLevelType
/**
* Log level in numeric form, used when deciding whether a certain log
* statement should generate a log event. Predefined levels are ErrorLevel (1)
* to DebugLevel (4). In case you want to add more levels, loggers need to
* be subscribed to their event bus channels manually.
*/
type LogLevel = Int with LogLevelType
final val ErrorLevel = 1.asInstanceOf[Int with LogLevelType]
final val WarningLevel = 2.asInstanceOf[Int with LogLevelType]
final val InfoLevel = 3.asInstanceOf[Int with LogLevelType]
final val DebugLevel = 4.asInstanceOf[Int with LogLevelType]
/**
* 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
}
/**
* Returns the LogLevel associated with the given event class.
* Defaults to DebugLevel.
*/
def levelFor(eventClass: Class[_ <: LogEvent]): LogLevel = {
if (classOf[Error].isAssignableFrom(eventClass)) ErrorLevel
else if (classOf[Warning].isAssignableFrom(eventClass)) WarningLevel
else if (classOf[Info].isAssignableFrom(eventClass)) InfoLevel
else if (classOf[Debug].isAssignableFrom(eventClass)) DebugLevel
else DebugLevel
}
/**
* Returns the event class associated with the given LogLevel
*/
def classFor(level: LogLevel): Class[_ <: LogEvent] = level match {
case ErrorLevel ⇒ classOf[Error]
case WarningLevel ⇒ classOf[Warning]
case InfoLevel ⇒ classOf[Info]
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
val errorFormatWithoutCause = "[ERROR] [%s] [%s] [%s] %s".intern
val warningFormat = "[WARN] [%s] [%s] [%s] %s".intern
val infoFormat = "[INFO] [%s] [%s] [%s] %s".intern
val debugFormat = "[DEBUG] [%s] [%s] [%s] %s".intern
/**
* Obtain LoggingAdapter for the given actor system and source object. This
* will use the system’s event stream and include the system’s address in the
* log source string.
*
* Do not use this if you want to supply a log category string (like
* “com.example.app.whatever”) unaltered, supply `system.eventStream` in this
* case or use
*
* {{{
* Logging(system, this.getClass)
* }}}
*
* The source is used to identify the source of this logging channel and
* must have a corresponding implicit LogSource[T] instance in scope; by
* default these are provided for Class[_], Actor, ActorRef and String types.
* See the companion object of [[akka.event.LogSource]] for details.
*
* You can add your own rules quite easily, see [[akka.event.LogSource]].
*/
def apply[T: LogSource](system: ActorSystem, logSource: T): LoggingAdapter = {
val (str, clazz) = LogSource(logSource, system)
new BusLogging(system.eventStream, str, clazz)
}
/**
* Obtain LoggingAdapter for the given logging bus and source object.
*
* The source is used to identify the source of this logging channel and
* must have a corresponding implicit LogSource[T] instance in scope; by
* default these are provided for Class[_], Actor, ActorRef and String types.
* See the companion object of [[akka.event.LogSource]] for details.
*
* You can add your own rules quite easily, see [[akka.event.LogSource]].
*/
def apply[T: LogSource](bus: LoggingBus, logSource: T): LoggingAdapter = {
val (str, clazz) = LogSource(logSource)
new BusLogging(bus, str, clazz)
}
/**
* Obtain LoggingAdapter for the given actor system and source object. This
* will use the system’s event stream and include the system’s address in the
* log source string.
*
* Do not use this if you want to supply a log category string (like
* “com.example.app.whatever”) unaltered, supply `system.eventStream` in this
* case or use
*
* {{{
* Logging.getLogger(system, this.getClass());
* }}}
*
* The source is used to identify the source of this logging channel and
* must have a corresponding implicit LogSource[T] instance in scope; by
* default these are provided for Class[_], Actor, ActorRef and String types.
* See the companion object of [[akka.event.LogSource]] for details.
*/
def getLogger(system: ActorSystem, logSource: AnyRef): LoggingAdapter = {
val (str, clazz) = LogSource.fromAnyRef(logSource, system)
new BusLogging(system.eventStream, str, clazz)
}
/**
* Obtain LoggingAdapter for the given logging bus and source object.
*
* The source is used to identify the source of this logging channel and
* must have a corresponding implicit LogSource[T] instance in scope; by
* default these are provided for Class[_], Actor, ActorRef and String types.
* See the companion object of [[akka.event.LogSource]] for details.
*/
def getLogger(bus: LoggingBus, logSource: AnyRef): LoggingAdapter = {
val (str, clazz) = LogSource.fromAnyRef(logSource)
new BusLogging(bus, str, clazz)
}
/**
* Artificial exception injected into Error events if no Throwable is
* supplied; used for getting a stack dump of error locations.
*/
class EventHandlerException extends AkkaException
/**
* Exception that wraps a LogEvent.
*/
class LogEventException(val event: LogEvent, cause: Throwable) extends NoStackTrace {
override def getMessage: String = event.toString
override def getCause: Throwable = cause
}
/**
* Base type of LogEvents
*/
sealed trait LogEvent {
/**
* The thread that created this log event
*/
@transient
val thread: Thread = Thread.currentThread
/**
* The LogLevel of this LogEvent
*/
def level: LogLevel
/**
* The source of this event
*/
def logSource: String
/**
* The class of the source of this event
*/
def logClass: Class[_]
/**
* The message, may be any object or null.
*/
def message: Any
}
/**
* For ERROR Logging
*/
case class Error(cause: Throwable, logSource: String, logClass: Class[_], message: Any = "") extends LogEvent {
def this(logSource: String, logClass: Class[_], message: Any) = this(Error.NoCause, logSource, logClass, message)
override def level = ErrorLevel
}
object Error {
def apply(logSource: String, logClass: Class[_], message: Any) = new Error(NoCause, logSource, logClass, message)
/** Null Object used for errors without cause Throwable */
object NoCause extends NoStackTrace
}
/**
* For WARNING Logging
*/
case class Warning(logSource: String, logClass: Class[_], message: Any = "") extends LogEvent {
override def level = WarningLevel
}
/**
* For INFO Logging
*/
case class Info(logSource: String, logClass: Class[_], message: Any = "") extends LogEvent {
override def level = InfoLevel
}
/**
* For DEBUG Logging
*/
case class Debug(logSource: String, logClass: Class[_], message: Any = "") extends LogEvent {
override 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 must handle this message, it can be used e.g. to register for more
* channels. When done, the logger must respond with a LoggerInitialized
* message. This is necessary to ensure that additional subscriptions are in
* effect when the logging system finished starting.
*/
case class InitializeLogger(bus: LoggingBus) extends NoSerializationVerificationNeeded
/**
* Response message each logger must send within 1 second after receiving the
* InitializeLogger request. If initialization takes longer, send the reply
* as soon as subscriptions are set-up.
*/
abstract class LoggerInitialized
case object LoggerInitialized extends LoggerInitialized {
/**
* Java API: get the singleton instance
*/
def getInstance = this
}
/**
* Java API to create a LoggerInitialized message.
*/
// weird return type due to binary compatibility
def loggerInitialized(): LoggerInitialized.type = LoggerInitialized
class LoggerInitializationException(msg: String) extends AkkaException(msg)
trait StdOutLogger {
import java.text.SimpleDateFormat
import java.util.Date
val dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.S")
def timestamp = dateFormat.format(new Date)
def print(event: Any) {
event match {
case e: Error ⇒ error(e)
case e: Warning ⇒ warning(e)
case e: Info ⇒ info(e)
case e: Debug ⇒ debug(e)
case e ⇒ warning(Warning(simpleName(this), this.getClass, "received unexpected event of class " + e.getClass + ": " + e))
}
}
def error(event: Error) = {
val f = if (event.cause == Error.NoCause) errorFormatWithoutCause else errorFormat
println(f.format(
timestamp,
event.thread.getName,
event.logSource,
event.message,
stackTraceFor(event.cause)))
}
def warning(event: Warning) =
println(warningFormat.format(
timestamp,
event.thread.getName,
event.logSource,
event.message))
def info(event: Info) =
println(infoFormat.format(
timestamp,
event.thread.getName,
event.logSource,
event.message))
def debug(event: Debug) =
println(debugFormat.format(
timestamp,
event.thread.getName,
event.logSource,
event.message))
}
/**
* 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 {
val path: ActorPath = new RootActorPath(Address("akka", "all-systems"), "/StandardOutLogger")
def provider: ActorRefProvider = throw new UnsupportedOperationException("StandardOutLogger does not provide")
override val toString = "StandardOutLogger"
override def !(message: Any)(implicit sender: ActorRef = null): Unit = print(message)
}
val StandardOutLogger = new StandardOutLogger
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(_) ⇒ sender ! LoggerInitialized
case event: LogEvent ⇒ print(event)
}
}
/**
* Returns the StackTrace for the given Throwable as a String
*/
def stackTraceFor(e: Throwable): String = e match {
case null | Error.NoCause ⇒ ""
case other ⇒
val sw = new java.io.StringWriter
val pw = new java.io.PrintWriter(sw)
other.printStackTrace(pw)
sw.toString
}
}
/**
* Logging wrapper to make nicer and optimize: provide template versions which
* evaluate .toString only if the log level is actually enabled. Typically used
* by obtaining an implementation from the Logging object:
*
*
*
* 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 LoggingAdapter {
/*
* implement these as precisely as needed/possible: always returning true
* just makes the notify... methods be called every time.
*/
def isErrorEnabled: Boolean
def isWarningEnabled: Boolean
def isInfoEnabled: Boolean
def isDebugEnabled: Boolean
/*
* These actually implement the passing on of the messages to be logged.
* Will not be called if is...Enabled returned false.
*/
protected def notifyError(message: String)
protected def notifyError(cause: Throwable, message: String)
protected def notifyWarning(message: String)
protected def notifyInfo(message: String)
protected def notifyDebug(message: String)
/*
* The rest is just the widening of the API for the user's convenience.
*/
def error(cause: Throwable, message: String) { if (isErrorEnabled) notifyError(cause, message) }
def error(cause: Throwable, template: String, arg1: Any) { if (isErrorEnabled) notifyError(cause, format1(template, arg1)) }
def error(cause: Throwable, template: String, arg1: Any, arg2: Any) { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2)) }
def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any) { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2, arg3)) }
def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2, arg3, arg4)) }
def error(message: String) { if (isErrorEnabled) notifyError(message) }
def error(template: String, arg1: Any) { if (isErrorEnabled) notifyError(format1(template, arg1)) }
def error(template: String, arg1: Any, arg2: Any) { if (isErrorEnabled) notifyError(format(template, arg1, arg2)) }
def error(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3)) }
def error(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3, arg4)) }
def warning(message: String) { if (isWarningEnabled) notifyWarning(message) }
def warning(template: String, arg1: Any) { if (isWarningEnabled) notifyWarning(format1(template, arg1)) }
def warning(template: String, arg1: Any, arg2: Any) { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2)) }
def warning(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3)) }
def warning(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3, arg4)) }
def info(message: String) { if (isInfoEnabled) notifyInfo(message) }
def info(template: String, arg1: Any) { if (isInfoEnabled) notifyInfo(format1(template, arg1)) }
def info(template: String, arg1: Any, arg2: Any) { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2)) }
def info(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3)) }
def info(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3, arg4)) }
def debug(message: String) { if (isDebugEnabled) notifyDebug(message) }
def debug(template: String, arg1: Any) { if (isDebugEnabled) notifyDebug(format1(template, arg1)) }
def debug(template: String, arg1: Any, arg2: Any) { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2)) }
def debug(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3)) }
def debug(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3, arg4)) }
def log(level: Logging.LogLevel, message: String) { if (isEnabled(level)) notifyLog(level, message) }
def log(level: Logging.LogLevel, template: String, arg1: Any) { if (isEnabled(level)) notifyLog(level, format1(template, arg1)) }
def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any) { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2)) }
def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any) { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2, arg3)) }
def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2, arg3, arg4)) }
final def isEnabled(level: Logging.LogLevel): Boolean = level match {
case Logging.ErrorLevel ⇒ isErrorEnabled
case Logging.WarningLevel ⇒ isWarningEnabled
case Logging.InfoLevel ⇒ isInfoEnabled
case Logging.DebugLevel ⇒ isDebugEnabled
}
final def notifyLog(level: Logging.LogLevel, message: String): Unit = level match {
case Logging.ErrorLevel ⇒ if (isErrorEnabled) notifyError(message)
case Logging.WarningLevel ⇒ if (isWarningEnabled) notifyWarning(message)
case Logging.InfoLevel ⇒ if (isInfoEnabled) notifyInfo(message)
case Logging.DebugLevel ⇒ if (isDebugEnabled) notifyDebug(message)
}
private def format1(t: String, arg: Any) = arg match {
case a: Array[_] if !a.getClass.getComponentType.isPrimitive ⇒ format(t, a: _*)
case a: Array[_] ⇒ format(t, (a map (_.asInstanceOf[AnyRef]): _*))
case x ⇒ format(t, x)
}
def format(t: String, arg: Any*) = {
val sb = new StringBuilder
var p = 0
var rest = t
while (p < arg.length) {
val index = rest.indexOf("{}")
if (index == -1) {
sb.append(rest).append(" WARNING arguments left: ").append(arg.length - p)
rest = ""
p = arg.length
} else {
sb.append(rest.substring(0, index))
sb.append(arg(p))
rest = rest.substring(index + 2)
p += 1
}
}
sb.append(rest)
sb.toString
}
}
class BusLogging(val bus: LoggingBus, val logSource: String, val logClass: Class[_]) extends LoggingAdapter {
import Logging._
def isErrorEnabled = bus.logLevel >= ErrorLevel
def isWarningEnabled = bus.logLevel >= WarningLevel
def isInfoEnabled = bus.logLevel >= InfoLevel
def isDebugEnabled = bus.logLevel >= DebugLevel
protected def notifyError(message: String) { bus.publish(Error(logSource, logClass, message)) }
protected def notifyError(cause: Throwable, message: String) { bus.publish(Error(cause, logSource, logClass, message)) }
protected def notifyWarning(message: String) { bus.publish(Warning(logSource, logClass, message)) }
protected def notifyInfo(message: String) { bus.publish(Info(logSource, logClass, message)) }
protected def notifyDebug(message: String) { bus.publish(Debug(logSource, logClass, message)) }
}