+slf #23409 support org.slf4j.Marker

This commit is contained in:
Konrad `ktoso` Malawski 2017-07-26 16:41:09 +09:00 committed by Johan Andrén
parent b8f20989c4
commit 00e7f21d66
4 changed files with 47 additions and 7 deletions

View file

@ -8,6 +8,7 @@ import java.util.concurrent.atomic.AtomicInteger
import akka.actor.ActorSystem.Settings import akka.actor.ActorSystem.Settings
import akka.actor._ import akka.actor._
import akka.annotation.{ DoNotInherit, InternalApi }
import akka.dispatch.RequiresMessageQueue import akka.dispatch.RequiresMessageQueue
import akka.event.Logging._ import akka.event.Logging._
import akka.util.ReentrantGuard import akka.util.ReentrantGuard
@ -1403,7 +1404,9 @@ trait DiagnosticLoggingAdapter extends LoggingAdapter {
def clearMDC(): Unit = mdc(emptyMDC) def clearMDC(): Unit = mdc(emptyMDC)
} }
final class LogMarker(val name: String) /** DO NOT INHERIT: Class is open only for use by akka-slf4j*/
@DoNotInherit
class LogMarker(val name: String)
object LogMarker { object LogMarker {
/** The Marker is internally transferred via MDC using using this key */ /** The Marker is internally transferred via MDC using using this key */
private[akka] final val MDCKey = "marker" private[akka] final val MDCKey = "marker"

View file

@ -559,6 +559,16 @@ A more advanced (including most Akka added information) example pattern would be
<pattern>%date{ISO8601} level=[%level] marker=[%marker] logger=[%logger] akkaSource=[%X{akkaSource}] sourceActorSystem=[%X{sourceActorSystem}] sourceThread=[%X{sourceThread}] mdc=[ticket-#%X{ticketNumber}: %X{ticketDesc}] - msg=[%msg]%n----%n</pattern> <pattern>%date{ISO8601} level=[%level] marker=[%marker] logger=[%logger] akkaSource=[%X{akkaSource}] sourceActorSystem=[%X{sourceActorSystem}] sourceThread=[%X{sourceThread}] mdc=[ticket-#%X{ticketNumber}: %X{ticketDesc}] - msg=[%msg]%n----%n</pattern>
``` ```
#### Using SLF4J's Markers
It is also possible to use the `org.slf4j.Marker` with the `LoggingAdapter` when using slf4j.
Since the akka-actor library avoids depending on any specific logging library, the support for this is included in `akka-slf4j`,
which provides the `Slf4jLogMarker` type which can be passed in as first argument instead of the logging framework agnostic LogMarker
type from `akka-actor`. The most notable difference between the two is that slf4j's Markers can have child markers, so one can
rely more information using them rather than just a single string.
<a id="jul"></a> <a id="jul"></a>
## java.util.logging ## java.util.logging

View file

@ -7,12 +7,9 @@ package akka.event.slf4j
import org.slf4j.{ MDC, Marker, MarkerFactory, Logger SLFLogger, LoggerFactory SLFLoggerFactory } import org.slf4j.{ MDC, Marker, MarkerFactory, Logger SLFLogger, LoggerFactory SLFLoggerFactory }
import akka.event.Logging._ import akka.event.Logging._
import akka.actor._ import akka.actor._
import akka.event.DummyClassForStringSources import akka.event.{ LogMarker, _ }
import akka.util.Helpers import akka.util.Helpers
import akka.event.LoggingFilter
import akka.event.EventStream
import akka.dispatch.RequiresMessageQueue import akka.dispatch.RequiresMessageQueue
import akka.event.LoggerMessageQueueSemantics
/** /**
* Base trait for all classes that wants to be able use the SLF4J logging infrastructure. * Base trait for all classes that wants to be able use the SLF4J logging infrastructure.
@ -111,7 +108,11 @@ class Slf4jLogger extends Actor with SLF4JLogging with RequiresMessageQueue[Logg
private final def markerIfPresent(event: LogEvent): Marker = private final def markerIfPresent(event: LogEvent): Marker =
event match { event match {
case m: LogEventWithMarker MarkerFactory.getMarker(m.marker.name) case m: LogEventWithMarker
m.marker match {
case slf4jMarker: Slf4jLogMarker slf4jMarker.marker
case marker MarkerFactory.getMarker(marker.name)
}
case _ null case _ null
} }
@ -141,3 +142,14 @@ class Slf4jLoggingFilter(settings: ActorSystem.Settings, eventStream: EventStrea
def isDebugEnabled(logClass: Class[_], logSource: String) = def isDebugEnabled(logClass: Class[_], logSource: String) =
(eventStream.logLevel >= DebugLevel) && Logger(logClass, logSource).isDebugEnabled (eventStream.logLevel >= DebugLevel) && Logger(logClass, logSource).isDebugEnabled
} }
/** Wraps [[org.slf4j.Marker]] */
final class Slf4jLogMarker(val marker: org.slf4j.Marker) extends LogMarker(name = marker.getName)
/** 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)
}

View file

@ -13,6 +13,7 @@ import ch.qos.logback.core.OutputStreamAppender
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import org.scalatest.BeforeAndAfterEach import org.scalatest.BeforeAndAfterEach
import org.slf4j.{ Marker, MarkerFactory }
object Slf4jLoggerSpec { object Slf4jLoggerSpec {
@ -27,6 +28,7 @@ object Slf4jLoggerSpec {
""" """
final case class StringWithMDC(s: String, mdc: Map[String, Any]) final case class StringWithMDC(s: String, mdc: Map[String, Any])
final case class StringWithSlf4jMarkerMDC(s: String, marker: Marker)
final case class StringWithMarker(s: String, marker: LogMarker) final case class StringWithMarker(s: String, marker: LogMarker)
final class LogProducer extends Actor with DiagnosticActorLogging { final class LogProducer extends Actor with DiagnosticActorLogging {
@ -38,6 +40,8 @@ object Slf4jLoggerSpec {
log.error(e, e.getMessage) log.error(e, e.getMessage)
case (s: String, x: Int, y: Int) case (s: String, x: Int, y: Int)
log.info(s, x, y) log.info(s, x, y)
case StringWithSlf4jMarkerMDC(s, m)
markLog.info(Slf4jLogMarker(m), s)
case StringWithMDC(s, mdc) case StringWithMDC(s, mdc)
log.mdc(mdc) log.mdc(mdc)
log.info(s) log.info(s)
@ -110,6 +114,17 @@ class Slf4jLoggerSpec extends AkkaSpec(Slf4jLoggerSpec.config) with BeforeAndAft
s should include("msg=[security-wise interesting message]") s should include("msg=[security-wise interesting message]")
} }
"log info with slf4j marker" in {
val slf4jMarker = MarkerFactory.getMarker("SLF")
slf4jMarker.add(MarkerFactory.getMarker("ADDED")) // slf4j markers can have children
producer ! StringWithSlf4jMarkerMDC("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]")
}
"put custom MDC values when specified" in { "put custom MDC values when specified" in {
producer ! StringWithMDC("Message with custom MDC values", Map("ticketNumber" 3671, "ticketDesc" "Custom MDC Values")) producer ! StringWithMDC("Message with custom MDC values", Map("ticketNumber" 3671, "ticketDesc" "Custom MDC Values"))