Rename sbt akka modules
Co-authored-by: Sean Glover <sean@seanglover.com>
This commit is contained in:
parent
b92b749946
commit
24c03cde19
2930 changed files with 1466 additions and 1462 deletions
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package org.apache.pekko.event.slf4j
|
||||
|
||||
import org.slf4j.{ Logger => SLFLogger, LoggerFactory => SLFLoggerFactory, MDC, Marker, MarkerFactory }
|
||||
|
||||
import org.apache.pekko
|
||||
import pekko.actor._
|
||||
import pekko.dispatch.RequiresMessageQueue
|
||||
import pekko.event.{ LogMarker, _ }
|
||||
import pekko.event.Logging._
|
||||
import pekko.util.{ unused, Helpers }
|
||||
|
||||
/**
|
||||
* Base trait for all classes that wants to be able use the SLF4J logging infrastructure.
|
||||
*/
|
||||
trait SLF4JLogging {
|
||||
@transient
|
||||
lazy val log = Logger(this.getClass.getName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Logger is a factory for obtaining SLF4J-Loggers
|
||||
*/
|
||||
object Logger {
|
||||
|
||||
/**
|
||||
* @param logger - which logger
|
||||
* @return a Logger that corresponds for the given logger name
|
||||
*/
|
||||
def apply(logger: String): SLFLogger = SLFLoggerFactory.getLogger(logger)
|
||||
|
||||
/**
|
||||
* @param logClass - the class to log for
|
||||
* @param logSource - the textual representation of the source of this log stream
|
||||
* @return a Logger for the specified parameters
|
||||
*/
|
||||
def apply(logClass: Class[_], logSource: String): SLFLogger = logClass match {
|
||||
case c if c == classOf[DummyClassForStringSources] => apply(logSource)
|
||||
case _ => SLFLoggerFactory.getLogger(logClass)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SLF4J Root Logger
|
||||
*/
|
||||
def root: SLFLogger = apply(SLFLogger.ROOT_LOGGER_NAME)
|
||||
}
|
||||
|
||||
/**
|
||||
* SLF4J logger.
|
||||
*
|
||||
* The thread in which the logging was performed is captured in
|
||||
* Mapped Diagnostic Context (MDC) with attribute name "sourceThread".
|
||||
*/
|
||||
class Slf4jLogger extends Actor with SLF4JLogging with RequiresMessageQueue[LoggerMessageQueueSemantics] {
|
||||
|
||||
val mdcThreadAttributeName = "sourceThread"
|
||||
val mdcActorSystemAttributeName = "sourceActorSystem"
|
||||
val mdcAkkaSourceAttributeName = "akkaSource"
|
||||
val mdcAkkaTimestamp = "akkaTimestamp"
|
||||
val mdcAkkaAddressAttributeName = "akkaAddress"
|
||||
val mdcAkkaUidAttributeName = "akkaUid"
|
||||
|
||||
private def akkaAddress = context.system.asInstanceOf[ExtendedActorSystem].provider.addressString
|
||||
private val akkaUid: String = context.system.asInstanceOf[ExtendedActorSystem].uid.toString
|
||||
|
||||
def receive = {
|
||||
|
||||
case event @ Error(cause, logSource, logClass, message) =>
|
||||
withMdc(logSource, event) {
|
||||
cause match {
|
||||
case Error.NoCause | null =>
|
||||
Logger(logClass, logSource).error(markerIfPresent(event), if (message != null) message.toString else null)
|
||||
case _ =>
|
||||
Logger(logClass, logSource).error(
|
||||
markerIfPresent(event),
|
||||
if (message != null) message.toString else cause.getLocalizedMessage,
|
||||
cause)
|
||||
}
|
||||
}
|
||||
|
||||
case event @ Warning(logSource, logClass, message) =>
|
||||
withMdc(logSource, event) {
|
||||
event match {
|
||||
case e: LogEventWithCause =>
|
||||
Logger(logClass, logSource).warn(
|
||||
markerIfPresent(event),
|
||||
if (message != null) message.toString else e.cause.getLocalizedMessage,
|
||||
e.cause)
|
||||
case _ =>
|
||||
Logger(logClass, logSource).warn(markerIfPresent(event), if (message != null) message.toString else null)
|
||||
}
|
||||
}
|
||||
|
||||
case event @ Info(logSource, logClass, message) =>
|
||||
withMdc(logSource, event) {
|
||||
Logger(logClass, logSource).info(markerIfPresent(event), "{}", message: Any)
|
||||
}
|
||||
|
||||
case event @ Debug(logSource, logClass, message) =>
|
||||
withMdc(logSource, event) {
|
||||
Logger(logClass, logSource).debug(markerIfPresent(event), "{}", message: Any)
|
||||
}
|
||||
|
||||
case InitializeLogger(_) =>
|
||||
log.info("Slf4jLogger started")
|
||||
sender() ! LoggerInitialized
|
||||
}
|
||||
|
||||
@inline
|
||||
final def withMdc(logSource: String, logEvent: LogEvent)(logStatement: => Unit): Unit = {
|
||||
logEvent match {
|
||||
case m: LogEventWithMarker if m.marker ne null =>
|
||||
val properties = m.marker.properties
|
||||
if (properties.nonEmpty) {
|
||||
properties.foreach { case (k, v) => MDC.put(k, String.valueOf(v)) }
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
|
||||
MDC.put(mdcAkkaSourceAttributeName, logSource)
|
||||
MDC.put(mdcThreadAttributeName, logEvent.thread.getName)
|
||||
MDC.put(mdcAkkaTimestamp, formatTimestamp(logEvent.timestamp))
|
||||
MDC.put(mdcActorSystemAttributeName, context.system.name)
|
||||
MDC.put(mdcAkkaAddressAttributeName, akkaAddress)
|
||||
MDC.put(mdcAkkaUidAttributeName, akkaUid)
|
||||
logEvent.mdc.foreach { case (k, v) => MDC.put(k, String.valueOf(v)) }
|
||||
|
||||
try logStatement
|
||||
finally {
|
||||
MDC.clear()
|
||||
}
|
||||
}
|
||||
|
||||
private final def markerIfPresent(event: LogEvent): Marker =
|
||||
event match {
|
||||
case m: LogEventWithMarker =>
|
||||
m.marker match {
|
||||
case null => null
|
||||
case slf4jMarker: Slf4jLogMarker => slf4jMarker.marker
|
||||
case marker => MarkerFactory.getMarker(marker.name)
|
||||
}
|
||||
case _ => null
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to provide a differently formatted timestamp
|
||||
* @param timestamp a "currentTimeMillis"-obtained timestamp
|
||||
* @return the given timestamp as a UTC String
|
||||
*/
|
||||
protected def formatTimestamp(timestamp: Long): String =
|
||||
Helpers.currentTimeMillisToUTCString(timestamp)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* [[pekko.event.LoggingFilter]] that uses the log level defined in the SLF4J
|
||||
* backend configuration (e.g. logback.xml) to filter log events before publishing
|
||||
* the log events to the `eventStream`.
|
||||
*/
|
||||
class Slf4jLoggingFilter(@unused settings: ActorSystem.Settings, eventStream: EventStream)
|
||||
extends LoggingFilterWithMarker {
|
||||
def isErrorEnabled(logClass: Class[_], logSource: String) =
|
||||
(eventStream.logLevel >= ErrorLevel) && Logger(logClass, logSource).isErrorEnabled
|
||||
def isWarningEnabled(logClass: Class[_], logSource: String) =
|
||||
(eventStream.logLevel >= WarningLevel) && Logger(logClass, logSource).isWarnEnabled
|
||||
def isInfoEnabled(logClass: Class[_], logSource: String) =
|
||||
(eventStream.logLevel >= InfoLevel) && Logger(logClass, logSource).isInfoEnabled
|
||||
def isDebugEnabled(logClass: Class[_], logSource: String) =
|
||||
(eventStream.logLevel >= DebugLevel) && Logger(logClass, logSource).isDebugEnabled
|
||||
|
||||
private def slf4jMarker(marker: LogMarker) = marker match {
|
||||
case null => null
|
||||
case slf4jMarker: Slf4jLogMarker => slf4jMarker.marker
|
||||
case marker => MarkerFactory.getMarker(marker.name)
|
||||
}
|
||||
|
||||
override def isErrorEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean =
|
||||
(eventStream.logLevel >= ErrorLevel) && Logger(logClass, logSource).isErrorEnabled(slf4jMarker(marker))
|
||||
override def isWarningEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean =
|
||||
(eventStream.logLevel >= WarningLevel) && Logger(logClass, logSource).isWarnEnabled(slf4jMarker(marker))
|
||||
override def isInfoEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean =
|
||||
(eventStream.logLevel >= InfoLevel) && Logger(logClass, logSource).isInfoEnabled(slf4jMarker(marker))
|
||||
override def isDebugEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean =
|
||||
(eventStream.logLevel >= DebugLevel) && Logger(logClass, logSource).isDebugEnabled(slf4jMarker(marker))
|
||||
|
||||
}
|
||||
|
||||
/** Wraps [[org.slf4j.Marker]] */
|
||||
final class Slf4jLogMarker(val marker: org.slf4j.Marker) extends LogMarker(name = marker.getName, Map.empty)
|
||||
|
||||
/** Factory for creating [[LogMarker]] that wraps [[org.slf4j.Marker]] */
|
||||
object Slf4jLogMarker {
|
||||
def apply(marker: org.slf4j.Marker): Slf4jLogMarker = new Slf4jLogMarker(marker)
|
||||
|
||||
/** Java API */
|
||||
def create(marker: org.slf4j.Marker): Slf4jLogMarker = apply(marker)
|
||||
}
|
||||
28
slf4j/src/test/resources/logback-test.xml
Normal file
28
slf4j/src/test/resources/logback-test.xml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%date{ISO8601} %-5level %logger %X{akkaSource} %X{sourceThread} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="TEST" class="org.apache.pekko.event.slf4j.Slf4jLoggerSpec$TestAppender">
|
||||
<encoder>
|
||||
<pattern>%date{ISO8601} level=[%level] marker=[%marker] logger=[%logger] mdc=[%mdc] - msg=[%msg]%n----%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<logger name="org.apache.pekko.event.slf4j.Slf4jLoggingFilterSpec$DebugLevelProducer"
|
||||
level="debug" additivity="false">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="org.apache.pekko.event.slf4j.Slf4jLoggingFilterSpec$WarningLevelProducer"
|
||||
level="warn" additivity="false">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="org.apache.pekko.event.slf4j.Slf4jLoggerSpec" level="info"
|
||||
additivity="false">
|
||||
<appender-ref ref="TEST" />
|
||||
</logger>
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package org.apache.pekko.event.slf4j
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import ch.qos.logback.core.OutputStreamAppender
|
||||
import language.postfixOps
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
import org.slf4j.{ Marker, MarkerFactory }
|
||||
|
||||
import org.apache.pekko
|
||||
import pekko.actor.{ Actor, DiagnosticActorLogging, Props }
|
||||
import pekko.event.{ LogMarker, Logging }
|
||||
import pekko.testkit.PekkoSpec
|
||||
|
||||
object Slf4jLoggerSpec {
|
||||
|
||||
// This test depends on logback configuration in src/test/resources/logback-test.xml
|
||||
|
||||
val config = """
|
||||
pekko {
|
||||
loglevel = INFO
|
||||
loggers = ["org.apache.pekko.event.slf4j.Slf4jLogger"]
|
||||
logger-startup-timeout = 30s
|
||||
}
|
||||
"""
|
||||
|
||||
final case class StringWithMDC(s: String, mdc: Map[String, Any])
|
||||
final case class StringWithMarker(s: String, marker: LogMarker)
|
||||
final case class StringWithSlf4jMarker(s: String, marker: Marker)
|
||||
final case class StringWithSlf4jMarkerMDC(s: String, marker: Marker, mdc: Map[String, Any])
|
||||
|
||||
final class LogProducer extends Actor with DiagnosticActorLogging {
|
||||
|
||||
val markLog = Logging.withMarker(this)
|
||||
|
||||
def receive = {
|
||||
case e: Exception =>
|
||||
log.error(e, e.getMessage)
|
||||
case (s: String, x: Int, y: Int) =>
|
||||
log.info(s, x, y)
|
||||
case StringWithSlf4jMarker(s, m) =>
|
||||
markLog.info(Slf4jLogMarker(m), s)
|
||||
case StringWithSlf4jMarkerMDC(s, mark, mdc) =>
|
||||
markLog.mdc(mdc)
|
||||
markLog.info(Slf4jLogMarker(mark), s)
|
||||
markLog.clearMDC()
|
||||
case StringWithMDC(s, mdc) =>
|
||||
log.mdc(mdc)
|
||||
log.info(s)
|
||||
log.clearMDC()
|
||||
case StringWithMarker(s, marker) =>
|
||||
markLog.info(marker, s)
|
||||
}
|
||||
}
|
||||
|
||||
class MyLogSource
|
||||
|
||||
val output = new ByteArrayOutputStream
|
||||
def outputString: String = output.toString("UTF-8")
|
||||
|
||||
class TestAppender[E] extends OutputStreamAppender[E] {
|
||||
|
||||
override def start(): Unit = {
|
||||
setOutputStream(output)
|
||||
super.start()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Slf4jLoggerSpec extends PekkoSpec(Slf4jLoggerSpec.config) with BeforeAndAfterEach {
|
||||
import Slf4jLoggerSpec._
|
||||
|
||||
val producer = system.actorOf(Props[LogProducer](), name = "logProducer")
|
||||
|
||||
override def beforeEach(): Unit = {
|
||||
output.reset()
|
||||
}
|
||||
|
||||
val sourceThreadRegex = "sourceThread=Slf4jLoggerSpec-pekko.actor.default-dispatcher-[1-9][0-9]*"
|
||||
|
||||
"Slf4jLogger" must {
|
||||
|
||||
"log error with stackTrace" in {
|
||||
producer ! new RuntimeException("Simulated error")
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("akkaSource=akka://Slf4jLoggerSpec/user/logProducer")
|
||||
s should include("akkaAddress=akka://Slf4jLoggerSpec")
|
||||
s should include("akkaUid=")
|
||||
s should include("level=[ERROR]")
|
||||
s should include("logger=[org.apache.pekko.event.slf4j.Slf4jLoggerSpec$LogProducer]")
|
||||
(s should include).regex(sourceThreadRegex)
|
||||
s should include("msg=[Simulated error]")
|
||||
s should include("java.lang.RuntimeException: Simulated error")
|
||||
s should include("at org.apache.pekko.event.slf4j.Slf4jLoggerSpec")
|
||||
}
|
||||
|
||||
"log info with parameters" in {
|
||||
producer ! (("test x={} y={}", 3, 17))
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("akkaSource=akka://Slf4jLoggerSpec/user/logProducer")
|
||||
s should include("akkaAddress=akka://Slf4jLoggerSpec")
|
||||
s should include("level=[INFO]")
|
||||
s should include("logger=[org.apache.pekko.event.slf4j.Slf4jLoggerSpec$LogProducer]")
|
||||
(s should include).regex(sourceThreadRegex)
|
||||
s should include("msg=[test x=3 y=17]")
|
||||
}
|
||||
|
||||
"log info with marker" in {
|
||||
producer ! StringWithMarker("security-wise interesting message", LogMarker("SECURITY"))
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("marker=[SECURITY]")
|
||||
s should include("msg=[security-wise interesting message]")
|
||||
}
|
||||
|
||||
"log info with marker and properties" in {
|
||||
producer ! StringWithMarker("interesting message", LogMarker("testMarker", Map("p1" -> 1, "p2" -> "B")))
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("marker=[testMarker]")
|
||||
s should include("p1=1")
|
||||
s should include("p2=B")
|
||||
s should include("msg=[interesting message]")
|
||||
}
|
||||
|
||||
"log info with slf4j marker" in {
|
||||
val slf4jMarker = MarkerFactory.getMarker("SLF")
|
||||
slf4jMarker.add(MarkerFactory.getMarker("ADDED")) // slf4j markers can have children
|
||||
producer ! StringWithSlf4jMarker("security-wise interesting message", slf4jMarker)
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("marker=[SLF [ ADDED ]]")
|
||||
s should include("msg=[security-wise interesting message]")
|
||||
}
|
||||
"log info with slf4j marker and MDC" in {
|
||||
val slf4jMarker = MarkerFactory.getMarker("SLF")
|
||||
slf4jMarker.add(MarkerFactory.getMarker("ADDED")) // slf4j markers can have children
|
||||
producer ! StringWithSlf4jMarkerMDC(
|
||||
"security-wise interesting message",
|
||||
slf4jMarker,
|
||||
Map("ticketNumber" -> 3671, "ticketDesc" -> "Custom MDC Values"))
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("marker=[SLF [ ADDED ]]")
|
||||
s should include("ticketDesc=Custom MDC Values")
|
||||
s should include("msg=[security-wise interesting message]")
|
||||
}
|
||||
|
||||
"put custom MDC values when specified" in {
|
||||
producer ! StringWithMDC(
|
||||
"Message with custom MDC values",
|
||||
Map("ticketNumber" -> 3671, "ticketDesc" -> "Custom MDC Values"))
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("akkaSource=akka://Slf4jLoggerSpec/user/logProducer")
|
||||
s should include("level=[INFO]")
|
||||
s should include("logger=[org.apache.pekko.event.slf4j.Slf4jLoggerSpec$LogProducer]")
|
||||
(s should include).regex(sourceThreadRegex)
|
||||
s should include("ticketDesc=Custom MDC Values")
|
||||
s should include("msg=[Message with custom MDC values]")
|
||||
}
|
||||
|
||||
"support null marker" in {
|
||||
producer ! StringWithMarker("security-wise interesting message", null)
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("msg=[security-wise interesting message]")
|
||||
}
|
||||
|
||||
"Support null values in custom MDC" in {
|
||||
producer ! StringWithMDC("Message with null custom MDC values", Map("ticketNumber" -> 3671, "ticketDesc" -> null))
|
||||
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("akkaSource=akka://Slf4jLoggerSpec/user/logProducer")
|
||||
s should include("level=[INFO]")
|
||||
s should include("logger=[org.apache.pekko.event.slf4j.Slf4jLoggerSpec$LogProducer]")
|
||||
println(s)
|
||||
(s should include).regex(sourceThreadRegex)
|
||||
s should include("ticketDesc=null")
|
||||
s should include("msg=[Message with null custom MDC values]")
|
||||
}
|
||||
|
||||
"include system info in akkaSource when creating Logging with system" in {
|
||||
val log = Logging(system, "org.apache.pekko.event.slf4j.Slf4jLoggerSpec.MyLogSource")
|
||||
log.info("test")
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("akkaSource=org.apache.pekko.event.slf4j.Slf4jLoggerSpec.MyLogSource(akka://Slf4jLoggerSpec)")
|
||||
s should include("logger=[org.apache.pekko.event.slf4j.Slf4jLoggerSpec.MyLogSource(akka://Slf4jLoggerSpec)]")
|
||||
}
|
||||
|
||||
"not include system info in akkaSource when creating Logging with system.eventStream" in {
|
||||
val log = Logging(system.eventStream, "org.apache.pekko.event.slf4j.Slf4jLoggerSpec.MyLogSource")
|
||||
log.info("test")
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("akkaSource=org.apache.pekko.event.slf4j.Slf4jLoggerSpec.MyLogSource")
|
||||
s should include("logger=[org.apache.pekko.event.slf4j.Slf4jLoggerSpec.MyLogSource]")
|
||||
}
|
||||
|
||||
"use short class name and include system info in akkaSource when creating Logging with system and class" in {
|
||||
val log = Logging(system, classOf[MyLogSource])
|
||||
log.info("test")
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("akkaSource=Slf4jLoggerSpec$MyLogSource(akka://Slf4jLoggerSpec)")
|
||||
s should include("logger=[org.apache.pekko.event.slf4j.Slf4jLoggerSpec$MyLogSource]")
|
||||
}
|
||||
|
||||
"use short class name in akkaSource when creating Logging with system.eventStream and class" in {
|
||||
val log = Logging(system.eventStream, classOf[MyLogSource])
|
||||
log.info("test")
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("akkaSource=Slf4jLoggerSpec$MyLogSource")
|
||||
s should include("logger=[org.apache.pekko.event.slf4j.Slf4jLoggerSpec$MyLogSource]")
|
||||
}
|
||||
|
||||
"include actorSystem name in sourceActorSystem" in {
|
||||
val log = Logging(system.eventStream, classOf[MyLogSource])
|
||||
log.info("test")
|
||||
awaitCond(outputString.contains("----"), 5 seconds)
|
||||
val s = outputString
|
||||
s should include("sourceActorSystem=Slf4jLoggerSpec")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package org.apache.pekko.event.slf4j
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import org.scalatest.BeforeAndAfterEach
|
||||
|
||||
import org.apache.pekko
|
||||
import pekko.actor.{ Actor, ActorLogging, Props }
|
||||
import pekko.actor.ActorRef
|
||||
import pekko.event.Logging
|
||||
import pekko.event.Logging.Debug
|
||||
import pekko.event.Logging.Info
|
||||
import pekko.event.Logging.InitializeLogger
|
||||
import pekko.event.Logging.LogEvent
|
||||
import pekko.event.Logging.LoggerInitialized
|
||||
import pekko.event.Logging.Warning
|
||||
import pekko.testkit.PekkoSpec
|
||||
import pekko.testkit.TestProbe
|
||||
|
||||
object Slf4jLoggingFilterSpec {
|
||||
|
||||
// This test depends on logback configuration in src/test/resources/logback-test.xml
|
||||
|
||||
val config = """
|
||||
pekko {
|
||||
loglevel = DEBUG # test verifies debug
|
||||
loggers = ["org.apache.pekko.event.slf4j.Slf4jLoggingFilterSpec$TestLogger"]
|
||||
logging-filter = "org.apache.pekko.event.slf4j.Slf4jLoggingFilter"
|
||||
}
|
||||
"""
|
||||
|
||||
final case class SetTarget(ref: ActorRef)
|
||||
|
||||
class TestLogger extends Actor {
|
||||
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 =>
|
||||
println("# event: " + event)
|
||||
target.foreach { _ ! event }
|
||||
}
|
||||
}
|
||||
|
||||
class DebugLevelProducer extends Actor with ActorLogging {
|
||||
def receive = {
|
||||
case s: String =>
|
||||
log.warning(s)
|
||||
log.info(s)
|
||||
println("# DebugLevelProducer: " + log.isDebugEnabled)
|
||||
log.debug(s)
|
||||
}
|
||||
}
|
||||
|
||||
class WarningLevelProducer extends Actor with ActorLogging {
|
||||
def receive = {
|
||||
case s: String =>
|
||||
log.warning(s)
|
||||
log.info(s)
|
||||
log.debug(s)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Slf4jLoggingFilterSpec extends PekkoSpec(Slf4jLoggingFilterSpec.config) with BeforeAndAfterEach {
|
||||
import Slf4jLoggingFilterSpec._
|
||||
|
||||
"Slf4jLoggingFilter" must {
|
||||
|
||||
"use configured LoggingFilter at debug log level in logback conf" in {
|
||||
val log1 = Logging(system, classOf[DebugLevelProducer])
|
||||
log1.isDebugEnabled should be(true)
|
||||
log1.isInfoEnabled should be(true)
|
||||
log1.isWarningEnabled should be(true)
|
||||
log1.isErrorEnabled should be(true)
|
||||
}
|
||||
|
||||
"use configured LoggingFilter at warning log level in logback conf" in {
|
||||
val log1 = Logging(system, classOf[WarningLevelProducer])
|
||||
log1.isDebugEnabled should be(false)
|
||||
log1.isInfoEnabled should be(false)
|
||||
log1.isWarningEnabled should be(true)
|
||||
log1.isErrorEnabled should be(true)
|
||||
}
|
||||
|
||||
"filter ActorLogging at debug log level with logback conf" in {
|
||||
val probe = TestProbe()
|
||||
system.eventStream.publish(SetTarget(probe.ref))
|
||||
probe.expectMsg("OK")
|
||||
val debugLevelProducer = system.actorOf(Props[DebugLevelProducer](), name = "debugLevelProducer")
|
||||
debugLevelProducer ! "test1"
|
||||
probe.expectMsgType[Warning].message should be("test1")
|
||||
probe.expectMsgType[Info].message should be("test1")
|
||||
probe.expectMsgType[Debug].message should be("test1")
|
||||
}
|
||||
|
||||
"filter ActorLogging at warning log level with logback conf" in {
|
||||
val probe = TestProbe()
|
||||
system.eventStream.publish(SetTarget(probe.ref))
|
||||
probe.expectMsg("OK")
|
||||
val debugLevelProducer = system.actorOf(Props[WarningLevelProducer](), name = "warningLevelProducer")
|
||||
debugLevelProducer ! "test2"
|
||||
probe.expectMsgType[Warning].message should be("test2")
|
||||
probe.expectNoMessage(500.millis)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue