0
# Akka SLF4J
1
2
Akka SLF4J provides seamless integration between Akka's actor-based logging system and the SLF4J logging facade. It enables developers to leverage existing SLF4J-compatible logging frameworks (like Logback, Log4J) within Akka applications while maintaining compatibility with Akka's event bus and logging levels.
3
4
The library includes the Slf4jLogger actor for processing Akka log events, the SLF4JLogging trait for easy logging access, utilities for configuring MDC (Mapped Diagnostic Context) support for structured logging, and filtering capabilities that respect SLF4J backend configuration.
5
6
## Package Information
7
8
- **Package Name**: akka-slf4j_2.12
9
- **Package Type**: maven
10
- **Language**: Scala
11
- **Installation**: Add to `build.sbt`: `"com.typesafe.akka" %% "akka-slf4j" % "2.8.8"`
12
- **Module**: `akka.event.slf4j`
13
14
## Core Imports
15
16
```scala
17
import akka.event.slf4j._
18
```
19
20
For specific components:
21
22
```scala
23
import akka.event.slf4j.{SLF4JLogging, Logger, Slf4jLogger, Slf4jLogMarker, Slf4jLoggingFilter}
24
```
25
26
## Basic Usage
27
28
### Configure Akka to use SLF4J Logger
29
30
```scala
31
// application.conf
32
akka {
33
loggers = ["akka.event.slf4j.Slf4jLogger"]
34
loglevel = "INFO"
35
logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
36
}
37
```
38
39
### Using SLF4JLogging trait in actors
40
41
```scala
42
import akka.actor.{Actor, ActorLogging}
43
import akka.event.slf4j.SLF4JLogging
44
45
class MyActor extends Actor with SLF4JLogging {
46
def receive = {
47
case message =>
48
log.info("Received message: {}", message)
49
log.debug("Processing in actor: {}", self.path)
50
}
51
}
52
```
53
54
### Manual logger creation
55
56
```scala
57
import akka.event.slf4j.Logger
58
59
class MyService {
60
private val log = Logger("com.example.MyService")
61
62
def processData(data: String): Unit = {
63
log.info("Processing data of length: {}", data.length)
64
if (data.isEmpty) {
65
log.warn("Empty data received")
66
}
67
}
68
}
69
```
70
71
## Architecture
72
73
Akka SLF4J is built around several key components:
74
75
- **SLF4JLogging trait**: Provides convenient `log` field initialization for classes
76
- **Logger object**: Factory for creating SLF4J logger instances with Akka-aware handling
77
- **Slf4jLogger actor**: Core actor that receives Akka log events and forwards them to SLF4J
78
- **Slf4jLoggingFilter**: Filter that respects SLF4J backend configuration for log level filtering
79
- **Slf4jLogMarker**: Wrapper for SLF4J markers to enable marker-based logging with Akka
80
- **MDC Support**: Automatic population of Mapped Diagnostic Context with Akka-specific information
81
82
## Capabilities
83
84
### SLF4J Logging Trait
85
86
Base trait that provides easy access to SLF4J logging infrastructure with lazy logger initialization.
87
88
```scala { .api }
89
trait SLF4JLogging {
90
@transient lazy val log: org.slf4j.Logger = Logger(this.getClass.getName)
91
}
92
```
93
94
Mix this trait into any class to get access to a logger instance named after the class.
95
96
### Logger Factory
97
98
Factory object for creating SLF4J logger instances with various initialization options.
99
100
```scala { .api }
101
object Logger {
102
def apply(logger: String): org.slf4j.Logger
103
def apply(logClass: Class[_], logSource: String): org.slf4j.Logger
104
def root: org.slf4j.Logger
105
}
106
```
107
108
- `apply(logger: String)`: Creates logger for the given logger name
109
- `apply(logClass: Class[_], logSource: String)`: Creates logger for specified class and source. Uses pattern matching to handle `DummyClassForStringSources` specially, falling back to `logSource` parameter for logger name
110
- `root`: Returns the SLF4J root logger
111
112
### SLF4J Logger Actor
113
114
Core actor that processes Akka logging events and forwards them to SLF4J with proper context and formatting.
115
116
```scala { .api }
117
class Slf4jLogger extends Actor with SLF4JLogging with RequiresMessageQueue[LoggerMessageQueueSemantics] {
118
def receive: Receive
119
protected def formatTimestamp(timestamp: Long): String
120
121
// MDC attribute name constants
122
val mdcThreadAttributeName: String = "sourceThread"
123
val mdcActorSystemAttributeName: String = "sourceActorSystem"
124
val mdcAkkaSourceAttributeName: String = "akkaSource"
125
val mdcAkkaTimestamp: String = "akkaTimestamp"
126
val mdcAkkaAddressAttributeName: String = "akkaAddress"
127
val mdcAkkaUidAttributeName: String = "akkaUid"
128
}
129
```
130
131
The actor handles these Akka log events:
132
- `Error` - Maps to SLF4J error level with exception handling
133
- `Warning` - Maps to SLF4J warn level
134
- `Info` - Maps to SLF4J info level
135
- `Debug` - Maps to SLF4J debug level
136
- `InitializeLogger` - Logger initialization message
137
138
139
### SLF4J Logging Filter
140
141
Logging filter that uses the SLF4J backend configuration to determine if log events should be published to the event stream.
142
143
```scala { .api }
144
class Slf4jLoggingFilter(@unused settings: ActorSystem.Settings, eventStream: EventStream)
145
extends LoggingFilterWithMarker {
146
147
def isErrorEnabled(logClass: Class[_], logSource: String): Boolean
148
def isWarningEnabled(logClass: Class[_], logSource: String): Boolean
149
def isInfoEnabled(logClass: Class[_], logSource: String): Boolean
150
def isDebugEnabled(logClass: Class[_], logSource: String): Boolean
151
152
// Marker-aware versions
153
def isErrorEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean
154
def isWarningEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean
155
def isInfoEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean
156
def isDebugEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean
157
}
158
```
159
160
This filter checks both Akka's event stream log level and the SLF4J backend configuration to determine if logging should occur.
161
162
### SLF4J Log Marker Support
163
164
Wrapper class and factory for integrating SLF4J markers with Akka's logging system.
165
166
```scala { .api }
167
final class Slf4jLogMarker(val marker: org.slf4j.Marker) extends LogMarker(name = marker.getName, properties = Map.empty)
168
169
object Slf4jLogMarker {
170
def apply(marker: org.slf4j.Marker): Slf4jLogMarker
171
def create(marker: org.slf4j.Marker): Slf4jLogMarker // Java API
172
}
173
```
174
175
Use with Akka's marker-based logging:
176
177
```scala
178
import akka.event.Logging
179
import org.slf4j.MarkerFactory
180
181
val marker = MarkerFactory.getMarker("BUSINESS_EVENT")
182
val markLog = Logging.withMarker(context.system, this)
183
markLog.info(Slf4jLogMarker(marker), "Business event occurred")
184
```
185
186
## Types
187
188
### Core Types
189
190
```scala { .api }
191
// From SLF4J API (external dependency)
192
trait org.slf4j.Logger {
193
def info(msg: String): Unit
194
def info(format: String, arg: Any): Unit
195
def warn(msg: String): Unit
196
def error(msg: String, t: Throwable): Unit
197
def debug(msg: String): Unit
198
def isInfoEnabled(): Boolean
199
def isDebugEnabled(): Boolean
200
// ... other standard SLF4J methods
201
}
202
203
trait org.slf4j.Marker {
204
def getName(): String
205
// ... other marker methods
206
}
207
```
208
209
### Akka Integration Types
210
211
```scala { .api }
212
// From akka-actor (dependency)
213
trait Actor {
214
def receive: Receive
215
def context: ActorContext
216
}
217
218
trait LoggingFilterWithMarker {
219
def isErrorEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean
220
def isWarningEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean
221
def isInfoEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean
222
def isDebugEnabled(logClass: Class[_], logSource: String, marker: LogMarker): Boolean
223
}
224
225
abstract class LogMarker(val name: String, val properties: Map[String, Any])
226
227
trait RequiresMessageQueue[T <: MessageQueue]
228
trait LoggerMessageQueueSemantics extends MessageQueue
229
230
// From akka-event
231
trait EventStream {
232
def logLevel: Int
233
}
234
235
class ActorSystem {
236
type Settings
237
}
238
239
// Additional types referenced in the API
240
trait LogEvent {
241
def timestamp: Long
242
def thread: Thread
243
def mdc: Map[String, Any]
244
}
245
246
trait LogEventWithMarker extends LogEvent {
247
def marker: LogMarker
248
}
249
250
trait LogEventWithCause extends LogEvent {
251
def cause: Throwable
252
}
253
254
case class Error(cause: Throwable, logSource: String, logClass: Class[_], message: Any) extends LogEvent with LogEventWithCause
255
case class Warning(logSource: String, logClass: Class[_], message: Any) extends LogEvent
256
case class Info(logSource: String, logClass: Class[_], message: Any) extends LogEvent
257
case class Debug(logSource: String, logClass: Class[_], message: Any) extends LogEvent
258
case class InitializeLogger(bus: EventStream) extends LogEvent
259
case object LoggerInitialized
260
261
trait DiagnosticActorLogging {
262
def log: DiagnosticLoggingAdapter
263
}
264
265
trait DiagnosticLoggingAdapter {
266
def mdc(mdc: Map[String, Any]): Unit
267
def clearMDC(): Unit
268
}
269
270
class DummyClassForStringSources
271
272
// From akka-actor types
273
trait ActorContext {
274
def system: ActorSystem
275
}
276
277
type Receive = PartialFunction[Any, Unit]
278
279
trait MessageQueue
280
281
// Log level constants
282
val ErrorLevel: Int
283
val WarningLevel: Int
284
val InfoLevel: Int
285
val DebugLevel: Int
286
```
287
288
## Configuration Examples
289
290
### Basic SLF4J Integration
291
292
```hocon
293
akka {
294
loggers = ["akka.event.slf4j.Slf4jLogger"]
295
loglevel = "DEBUG"
296
logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
297
logger-startup-timeout = 30s
298
}
299
```
300
301
### With Logback Backend
302
303
Create `logback.xml`:
304
305
```xml
306
<configuration>
307
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
308
<encoder>
309
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level [%X{akkaSource}] %logger{36} - %msg%n</pattern>
310
</encoder>
311
</appender>
312
313
<logger name="akka" level="INFO" />
314
<root level="DEBUG">
315
<appender-ref ref="STDOUT" />
316
</root>
317
</configuration>
318
```
319
320
### Advanced MDC Usage
321
322
The logger automatically populates MDC with Akka-specific context:
323
324
```scala
325
// These MDC keys are automatically available in your logging pattern:
326
// sourceThread - Thread where logging occurred
327
// sourceActorSystem - Name of the actor system
328
// akkaSource - Akka logging source
329
// akkaTimestamp - Formatted timestamp
330
// akkaAddress - Actor system address
331
// akkaUid - Actor system unique identifier
332
```
333
334
Access in logback pattern:
335
336
```xml
337
<pattern>%d [%X{sourceThread}] [%X{akkaSource}] %-5level %logger - %msg%n</pattern>
338
```
339
340
## Error Handling
341
342
The SLF4J integration handles various error scenarios:
343
344
- **Null messages**: Handled gracefully without throwing exceptions
345
- **Missing SLF4J backend**: Falls back to no-op logging behavior
346
- **Actor system shutdown**: Proper cleanup of MDC context
347
- **Thread context**: MDC is properly cleared after each log statement to prevent context leakage
348
349
## Dependencies
350
351
This module requires:
352
353
- `akka-actor` - Core Akka actor system
354
- `slf4j-api` (version 1.7.36) - SLF4J logging facade
355
- SLF4J implementation (like Logback, Log4J2) - Choose based on your needs
356
357
Add to your `build.sbt`:
358
359
```scala
360
libraryDependencies ++= Seq(
361
"com.typesafe.akka" %% "akka-slf4j" % "2.8.8",
362
"ch.qos.logback" % "logback-classic" % "1.2.12" // or your preferred SLF4J implementation
363
)
364
```