SLF4J integration for Akka logging system enabling seamless logging with MDC context support.
npx @tessl/cli install tessl/maven-com-typesafe-akka--akka-slf4j-2-10@2.3.0Akka SLF4J provides seamless integration between Akka's actor-based logging system and the Simple Logging Facade for Java (SLF4J) framework. It enables Akka applications to leverage SLF4J's flexible logging architecture while maintaining compatibility with Akka's built-in logging mechanisms.
libraryDependencies += "com.typesafe.akka" %% "akka-slf4j" % "2.3.16"com.typesafe.akka:akka-slf4j_2.10:2.3.16import akka.event.slf4j._For specific components:
import akka.event.slf4j.{SLF4JLogging, Logger, Slf4jLogger}import akka.actor.{ActorSystem, ActorLogging, Actor, Props}
import akka.event.slf4j.{SLF4JLogging, Slf4jLogger}
import com.typesafe.config.ConfigFactory
// Configure Akka to use SLF4J logger
val system = ActorSystem("MySystem", ConfigFactory.parseString("""
akka {
loggers = ["akka.event.slf4j.Slf4jLogger"]
loglevel = "INFO"
}
"""))
// Use SLF4JLogging trait in your classes
class MyService extends SLF4JLogging {
def process(data: String): Unit = {
log.info("Processing data: {}", data)
log.debug("Debug information")
}
}
// Use in actors with ActorLogging
class MyActor extends Actor with ActorLogging {
def receive = {
case msg =>
log.info("Received message: {}", msg)
}
}
val myActor = system.actorOf(Props[MyActor], "myActor")Akka SLF4J provides three key components for logging integration:
The integration automatically populates SLF4J's Mapped Diagnostic Context (MDC) with valuable debugging information including source thread names, Akka source identifiers, and timestamps.
Base trait for classes that want to use the SLF4J logging infrastructure.
trait SLF4JLogging {
/** Lazy-initialized logger for the class name */
@transient
lazy val log: org.slf4j.Logger
}Usage Example:
import akka.event.slf4j.SLF4JLogging
class UserService extends SLF4JLogging {
def createUser(name: String): User = {
log.info("Creating user: {}", name)
// ... business logic
log.debug("User created successfully")
user
}
}Factory object for obtaining SLF4J logger instances.
object Logger {
/**
* Creates a logger for the given logger name
* @param logger Logger name as string
* @return SLF4J Logger instance
*/
def apply(logger: String): org.slf4j.Logger
/**
* Creates a logger for the specified class and source
* @param logClass The class to log for
* @param logSource The textual representation of the source
* @return SLF4J Logger instance
*/
def apply(logClass: Class[_], logSource: String): org.slf4j.Logger
/**
* Returns the SLF4J Root Logger
* @return Root logger instance
*/
def root: org.slf4j.Logger
}Usage Examples:
import akka.event.slf4j.Logger
// Logger by name
val namedLogger = Logger("com.mycompany.MyClass")
// Logger by class
val classLogger = Logger(classOf[MyService], "MyService")
// Root logger
val rootLogger = Logger.rootCore logging actor that handles Akka log events and manages SLF4J MDC context.
class Slf4jLogger extends Actor with SLF4JLogging {
/** MDC attribute name for source thread */
val mdcThreadAttributeName: String = "sourceThread"
/** MDC attribute name for Akka source */
val mdcAkkaSourceAttributeName: String = "akkaSource"
/** MDC attribute name for Akka timestamp */
val mdcAkkaTimestamp: String = "akkaTimestamp"
/** Actor receive method handling log events */
def receive: Receive
/**
* Sets MDC context for logging operations (inline final method)
* @param logSource The source of the log event
* @param logEvent The log event containing metadata
* @param logStatement The logging statement to execute (call-by-name)
*/
@inline
final def withMdc(logSource: String, logEvent: LogEvent)(logStatement: => Unit): Unit
/**
* Formats timestamp to UTC string (overridable)
* @param timestamp Timestamp in milliseconds
* @return Formatted UTC timestamp string
*/
protected def formatTimestamp(timestamp: Long): String
}The Slf4jLogger actor handles these Akka log event types:
// Error events with optional exception
case class Error(cause: Throwable, logSource: String, logClass: Class[_], message: Any)
// Warning events
case class Warning(logSource: String, logClass: Class[_], message: Any)
// Info events
case class Info(logSource: String, logClass: Class[_], message: Any)
// Debug events
case class Debug(logSource: String, logClass: Class[_], message: Any)
// Logger initialization (responds with LoggerInitialized)
case class InitializeLogger(bus: LoggingBus)
// Response to logger initialization
case object LoggerInitializedConfigure Akka to use the SLF4J logger in your application.conf:
akka {
# Use SLF4J logger
loggers = ["akka.event.slf4j.Slf4jLogger"]
# Set log level
loglevel = "INFO"
# Optional: Set startup timeout
logger-startup-timeout = 30s
}The logger automatically populates SLF4J's Mapped Diagnostic Context with:
Example MDC usage with custom values:
import akka.actor.{Actor, DiagnosticActorLogging}
import akka.event.Logging.MDC
class OrderProcessor extends Actor with DiagnosticActorLogging {
def receive = {
case ProcessOrder(orderId, customerId) =>
// Set custom MDC values
log.mdc(Map(
"orderId" -> orderId,
"customerId" -> customerId
))
log.info("Processing order")
// Clear MDC when done
log.clearMDC()
}
}The logger handles exceptions in log events by:
Example error logging:
import akka.actor.{Actor, ActorLogging}
class DataProcessor extends Actor with ActorLogging {
def receive = {
case ProcessData(data) =>
try {
// ... process data
} catch {
case ex: ValidationException =>
log.error(ex, "Data validation failed for: {}", data.id)
case ex: Exception =>
log.error(ex, "Unexpected error processing data")
}
}
}// Re-exported from org.slf4j
type Logger = org.slf4j.Logger
// Akka logging system types (from akka.event)
trait LoggingBus
// Akka logging event types (from akka.event.Logging)
sealed trait LogEvent {
def logSource: String
def logClass: Class[_]
def message: Any
def timestamp: Long
def thread: Thread
def mdc: Map[String, Any]
}
case class Error(
cause: Throwable,
logSource: String,
logClass: Class[_],
message: Any
) extends LogEvent
case class Warning(
logSource: String,
logClass: Class[_],
message: Any
) extends LogEvent
case class Info(
logSource: String,
logClass: Class[_],
message: Any
) extends LogEvent
case class Debug(
logSource: String,
logClass: Class[_],
message: Any
) extends LogEvent