From c9969b0bea1ad49c6aa47a9fa0713ee360995bbe Mon Sep 17 00:00:00 2001 From: Thomas Smith Date: Mon, 5 Mar 2018 09:10:14 +0100 Subject: [PATCH] Add log() method to typed Logging API #24648 --- .../typed/scaladsl/ActorLoggingSpec.scala | 23 ++++- .../main/scala/akka/actor/typed/Logger.scala | 95 +++++++++++++++++++ .../internal/adapter/LoggerAdapterImpl.scala | 50 +++++++++- 3 files changed, 165 insertions(+), 3 deletions(-) diff --git a/akka-actor-typed-tests/src/test/scala/akka/actor/typed/scaladsl/ActorLoggingSpec.scala b/akka-actor-typed-tests/src/test/scala/akka/actor/typed/scaladsl/ActorLoggingSpec.scala index fad7b0cff2..0cd8c5fb6d 100644 --- a/akka-actor-typed-tests/src/test/scala/akka/actor/typed/scaladsl/ActorLoggingSpec.scala +++ b/akka-actor-typed-tests/src/test/scala/akka/actor/typed/scaladsl/ActorLoggingSpec.scala @@ -48,13 +48,16 @@ class ActorLoggingSpec extends ActorTestKit with TypedAkkaSpec { "pass markers to the log" in { EventFilter.custom({ case event: LogEventWithMarker if event.marker == marker ⇒ true - }, occurrences = 5).intercept( + }, occurrences = 9).intercept( spawn(Behaviors.setup[Any] { ctx ⇒ ctx.log.debug(marker, "whatever") ctx.log.info(marker, "whatever") ctx.log.warning(marker, "whatever") ctx.log.error(marker, "whatever") ctx.log.error(marker, cause, "whatever") + Logging.AllLogLevels.foreach(level ⇒ { + ctx.log.log(level, marker, "whatever") + }) Behaviors.stopped }) ) @@ -78,7 +81,7 @@ class ActorLoggingSpec extends ActorTestKit with TypedAkkaSpec { EventFilter.custom({ case _ ⇒ true // any is fine, we're just after the right count of statements reaching the listener - }, occurrences = 72).intercept { + }, occurrences = 120).intercept { spawn(Behaviors.setup[String] { ctx ⇒ ctx.log.debug("message") ctx.log.debug("{}", "arg1") @@ -158,6 +161,22 @@ class ActorLoggingSpec extends ActorTestKit with TypedAkkaSpec { ctx.log.error(marker, cause, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4") ctx.log.error(marker, cause, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5")) + Logging.AllLogLevels.foreach(level ⇒ { + ctx.log.log(level, "message") + ctx.log.log(level, "{}", "arg1") + ctx.log.log(level, "{} {}", "arg1", "arg2") + ctx.log.log(level, "{} {} {}", "arg1", "arg2", "arg3") + ctx.log.log(level, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4") + ctx.log.log(level, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5")) + + ctx.log.log(level, marker, "message") + ctx.log.log(level, marker, "{}", "arg1") + ctx.log.log(level, marker, "{} {}", "arg1", "arg2") + ctx.log.log(level, marker, "{} {} {}", "arg1", "arg2", "arg3") + ctx.log.log(level, marker, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4") + ctx.log.log(level, marker, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5")) + }) + Behaviors.stopped }) } diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/Logger.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/Logger.scala index eaa212f47d..cd9382a088 100644 --- a/akka-actor-typed/src/main/scala/akka/actor/typed/Logger.scala +++ b/akka-actor-typed/src/main/scala/akka/actor/typed/Logger.scala @@ -4,6 +4,7 @@ package akka.actor.typed import akka.annotation.{ DoNotInherit, InternalApi } +import akka.event.Logging.{ ErrorLevel, WarningLevel, InfoLevel, DebugLevel, LogLevel } /** * A log marker is an additional metadata tag supported by some logging backends to identify "special" log events. @@ -94,6 +95,19 @@ abstract class Logger private[akka] () { */ def isDebugEnabled: Boolean + /** + * Whether a log level is enabled on the actor system level, may not represent the setting all the way to the + * logger implementation, but when it does it allows avoiding unnecessary resource usage for log entries that + * will not actually end up in any logger output. + */ + def isLevelEnabled(logLevel: LogLevel): Boolean = logLevel match { + case ErrorLevel ⇒ isErrorEnabled + case WarningLevel ⇒ isWarningEnabled + case InfoLevel ⇒ isInfoEnabled + case DebugLevel ⇒ isDebugEnabled + case _ ⇒ false + } + // message only error logging /** @@ -556,4 +570,85 @@ abstract class Logger private[akka] () { */ def debug(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit + // message any level logging + + /** + * Log message at the specified level. + * + * @see [[Logger]] + */ + def log(level: LogLevel, message: String): Unit + /** + * Message template with 1 replacement argument. + * + * If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when + * there are more than four arguments. + * + * @see [[Logger]] + */ + def log(level: LogLevel, template: String, arg1: Any): Unit + /** + * Message template with 2 replacement arguments. + * + * @see [[Logger]] + */ + def log(level: LogLevel, template: String, arg1: Any, arg2: Any): Unit + /** + * Message template with 3 replacement arguments. + * + * @see [[Logger]] + */ + def log(level: LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any): Unit + /** + * Message template with 4 replacement arguments. For more parameters see the single replacement version of this method. + * + * @see [[Logger]] + */ + def log(level: LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit + + // marker logging at any level + + /** + * Log message at the specified level. + * + * The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special". + * + * @see [[Logger]] + */ + def log(level: LogLevel, marker: LogMarker, message: String): Unit + /** + * Message template with 1 replacement argument. + * + * The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special". + * + * If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when + * there are more than four arguments. + * + * @see [[Logger]] + */ + def log(level: LogLevel, marker: LogMarker, template: String, arg1: Any): Unit + /** + * Message template with 2 replacement arguments. + * + * The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special". + * + * @see [[Logger]] + */ + def log(level: LogLevel, marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit + /** + * Message template with 3 replacement arguments. + * + * The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special". + * + * @see [[Logger]] + */ + def log(level: LogLevel, marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit + /** + * Message template with 4 replacement arguments. For more parameters see the single replacement version of this method. + * + * The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special". + * + * @see [[Logger]] + */ + def log(level: LogLevel, marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit } diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/internal/adapter/LoggerAdapterImpl.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/internal/adapter/LoggerAdapterImpl.scala index fb61cea692..c8b5fe2021 100644 --- a/akka-actor-typed/src/main/scala/akka/actor/typed/internal/adapter/LoggerAdapterImpl.scala +++ b/akka-actor-typed/src/main/scala/akka/actor/typed/internal/adapter/LoggerAdapterImpl.scala @@ -5,7 +5,7 @@ package akka.actor.typed.internal.adapter import akka.actor.typed.{ LogMarker, Logger } import akka.annotation.InternalApi -import akka.event.Logging.{ Debug, Error, Info, Warning } +import akka.event.Logging.{ Debug, DebugLevel, Error, ErrorLevel, Info, InfoLevel, LogLevel, Warning, WarningLevel } import akka.event.{ LoggingBus, LoggingFilter, LogMarker ⇒ UntypedLM } import akka.util.OptionVal @@ -262,6 +262,46 @@ private[akka] class LoggerAdapterImpl(bus: LoggingBus, logClass: Class[_], logSo if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3, arg4), OptionVal.Some(marker)) } + override def log(level: LogLevel, message: String): Unit = { + if (isLevelEnabled(level)) notify(level, message, OptionVal.None) + } + + override def log(level: LogLevel, template: String, arg1: Any): Unit = { + if (isLevelEnabled(level)) notify(level, format(template, arg1), OptionVal.None) + } + + override def log(level: LogLevel, template: String, arg1: Any, arg2: Any): Unit = { + if (isLevelEnabled(level)) notify(level, format(template, arg1, arg2), OptionVal.None) + } + + override def log(level: LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = { + if (isLevelEnabled(level)) notify(level, format(template, arg1, arg2, arg3), OptionVal.None) + } + + override def log(level: LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = { + if (isLevelEnabled(level)) notify(level, format(template, arg1, arg2, arg3, arg4), OptionVal.None) + } + + override def log(level: LogLevel, marker: LogMarker, message: String): Unit = { + if (isLevelEnabled(level)) notify(level, message, OptionVal.Some(marker)) + } + + override def log(level: LogLevel, marker: LogMarker, template: String, arg1: Any): Unit = { + if (isLevelEnabled(level)) notify(level, format(template, arg1), OptionVal.Some(marker)) + } + + override def log(level: LogLevel, marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit = { + if (isLevelEnabled(level)) notify(level, format(template, arg1, arg2), OptionVal.Some(marker)) + } + + override def log(level: LogLevel, marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = { + if (isLevelEnabled(level)) notify(level, format(template, arg1, arg2, arg3), OptionVal.Some(marker)) + } + + override def log(level: LogLevel, marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = { + if (isLevelEnabled(level)) notify(level, format(template, arg1, arg2, arg3, arg4), OptionVal.Some(marker)) + } + protected def notifyError(message: String, cause: OptionVal[Throwable], marker: OptionVal[LogMarker]): Unit = { val error = cause match { case OptionVal.Some(cause) ⇒ @@ -309,6 +349,14 @@ private[akka] class LoggerAdapterImpl(bus: LoggingBus, logClass: Class[_], logSo bus.publish(debug) } + protected def notify(level: LogLevel, message: String, marker: OptionVal[LogMarker]): Unit = level match { + case ErrorLevel ⇒ notifyDebug(message, marker) + case WarningLevel ⇒ notifyWarning(message, marker, OptionVal.None) + case InfoLevel ⇒ notifyInfo(message, marker) + case DebugLevel ⇒ notifyDebug(message, marker) + case _ ⇒ () + } + /** * If `arg` is an `Array` it will be expanded into replacement arguments, which is useful when * there are more than four arguments.