0
# Fluent Logging API
1
2
SLF4J 2.x fluent interface for building complex log events with structured data, lazy evaluation, and method chaining. This API enables modern logging patterns with key-value pairs, conditional logging, and deferred message construction.
3
4
## Capabilities
5
6
### Event Builder Creation
7
8
Create fluent logging event builders for each log level.
9
10
```java { .api }
11
/**
12
* Create a fluent logging event builder at TRACE level
13
* @return LoggingEventBuilder for TRACE level
14
*/
15
LoggingEventBuilder atTrace();
16
17
/**
18
* Create a fluent logging event builder at DEBUG level
19
* @return LoggingEventBuilder for DEBUG level
20
*/
21
LoggingEventBuilder atDebug();
22
23
/**
24
* Create a fluent logging event builder at INFO level
25
* @return LoggingEventBuilder for INFO level
26
*/
27
LoggingEventBuilder atInfo();
28
29
/**
30
* Create a fluent logging event builder at WARN level
31
* @return LoggingEventBuilder for WARN level
32
*/
33
LoggingEventBuilder atWarn();
34
35
/**
36
* Create a fluent logging event builder at ERROR level
37
* @return LoggingEventBuilder for ERROR level
38
*/
39
LoggingEventBuilder atError();
40
```
41
42
**Usage Examples:**
43
44
```java
45
// Create event builders
46
LoggingEventBuilder infoEvent = logger.atInfo();
47
LoggingEventBuilder errorEvent = logger.atError();
48
49
// Builders are only created if the level is enabled
50
if (logger.isDebugEnabled()) {
51
LoggingEventBuilder debugEvent = logger.atDebug();
52
}
53
```
54
55
### Basic Event Configuration
56
57
Configure basic properties of the log event.
58
59
```java { .api }
60
/**
61
* Set the exception cause for this log event
62
* @param cause The throwable cause
63
* @return This event builder for chaining
64
*/
65
LoggingEventBuilder setCause(Throwable cause);
66
67
/**
68
* Add a marker to this log event
69
* @param marker The marker to add
70
* @return This event builder for chaining
71
*/
72
LoggingEventBuilder addMarker(Marker marker);
73
74
/**
75
* Set the log message
76
* @param message The message string
77
* @return This event builder for chaining
78
*/
79
LoggingEventBuilder setMessage(String message);
80
81
/**
82
* Set the log message using a supplier (lazy evaluation)
83
* @param messageSupplier Supplier that provides the message
84
* @return This event builder for chaining
85
*/
86
LoggingEventBuilder setMessage(Supplier<String> messageSupplier);
87
```
88
89
**Usage Examples:**
90
91
```java
92
// Basic event configuration
93
logger.atInfo()
94
.setMessage("User login successful")
95
.log();
96
97
// With marker and exception
98
Marker securityMarker = MarkerFactory.getMarker("SECURITY");
99
logger.atError()
100
.addMarker(securityMarker)
101
.setCause(exception)
102
.setMessage("Authentication failed")
103
.log();
104
105
// Lazy message evaluation
106
logger.atDebug()
107
.setMessage(() -> "Expensive computation result: " + computeExpensiveValue())
108
.log();
109
```
110
111
### Parameterized Messages
112
113
Add arguments for parameterized messages with type safety.
114
115
```java { .api }
116
/**
117
* Add an argument for parameterized message
118
* @param p The argument object
119
* @return This event builder for chaining
120
*/
121
LoggingEventBuilder addArgument(Object p);
122
123
/**
124
* Add a lazy-evaluated argument using a supplier
125
* @param objectSupplier Supplier that provides the argument
126
* @return This event builder for chaining
127
*/
128
LoggingEventBuilder addArgument(Supplier<?> objectSupplier);
129
```
130
131
**Usage Examples:**
132
133
```java
134
// Parameterized message with arguments
135
logger.atInfo()
136
.setMessage("User {} logged in from {}")
137
.addArgument(username)
138
.addArgument(ipAddress)
139
.log();
140
141
// Lazy argument evaluation
142
logger.atDebug()
143
.setMessage("Processing item {} with result {}")
144
.addArgument(itemId)
145
.addArgument(() -> performExpensiveCalculation(itemId))
146
.log();
147
148
// Multiple arguments
149
logger.atInfo()
150
.setMessage("Transfer of ${} from {} to {} completed")
151
.addArgument(amount)
152
.addArgument(fromAccount)
153
.addArgument(toAccount)
154
.log();
155
```
156
157
### Structured Data (Key-Value Pairs)
158
159
Add structured data as key-value pairs for modern observability platforms.
160
161
```java { .api }
162
/**
163
* Add a key-value pair to the log event
164
* @param key The key name
165
* @param value The value object
166
* @return This event builder for chaining
167
*/
168
LoggingEventBuilder addKeyValue(String key, Object value);
169
170
/**
171
* Add a key-value pair with lazy-evaluated value
172
* @param key The key name
173
* @param valueSupplier Supplier that provides the value
174
* @return This event builder for chaining
175
*/
176
LoggingEventBuilder addKeyValue(String key, Supplier<Object> valueSupplier);
177
```
178
179
**Usage Examples:**
180
181
```java
182
// Structured logging with key-value pairs
183
logger.atInfo()
184
.setMessage("API request processed")
185
.addKeyValue("userId", userId)
186
.addKeyValue("endpoint", "/api/users")
187
.addKeyValue("method", "GET")
188
.addKeyValue("responseTime", responseTime)
189
.addKeyValue("statusCode", 200)
190
.log();
191
192
// Lazy key-value evaluation
193
logger.atDebug()
194
.setMessage("Cache operation completed")
195
.addKeyValue("operation", "get")
196
.addKeyValue("key", cacheKey)
197
.addKeyValue("hit", () -> cache.containsKey(cacheKey))
198
.addKeyValue("size", () -> cache.size())
199
.log();
200
201
// Complex structured data
202
logger.atWarn()
203
.setMessage("Rate limit exceeded")
204
.addKeyValue("clientId", clientId)
205
.addKeyValue("requestsPerMinute", requestCount)
206
.addKeyValue("limit", rateLimitThreshold)
207
.addKeyValue("windowStart", windowStart.toString())
208
.addKeyValue("action", "throttle")
209
.log();
210
```
211
212
### Event Execution
213
214
Execute the configured log event.
215
216
```java { .api }
217
/**
218
* Execute the log event with configured settings
219
*/
220
void log();
221
222
/**
223
* Set message and execute the log event
224
* @param message The log message
225
*/
226
void log(String message);
227
228
/**
229
* Set message with one argument and execute
230
* @param message The log message with placeholder
231
* @param arg The argument
232
*/
233
void log(String message, Object arg);
234
235
/**
236
* Set message with two arguments and execute
237
* @param message The log message with placeholders
238
* @param arg0 The first argument
239
* @param arg1 The second argument
240
*/
241
void log(String message, Object arg0, Object arg1);
242
243
/**
244
* Set message with multiple arguments and execute
245
* @param message The log message with placeholders
246
* @param args The arguments
247
*/
248
void log(String message, Object... args);
249
250
/**
251
* Set lazy message and execute
252
* @param messageSupplier Supplier that provides the message
253
*/
254
void log(Supplier<String> messageSupplier);
255
```
256
257
**Usage Examples:**
258
259
```java
260
// Build and execute separately
261
LoggingEventBuilder event = logger.atInfo()
262
.addKeyValue("operation", "user_creation")
263
.addKeyValue("userId", newUserId);
264
265
if (isSuccessful) {
266
event.setMessage("User created successfully").log();
267
} else {
268
event.setMessage("User creation failed").log();
269
}
270
271
// Set message and execute in one call
272
logger.atInfo()
273
.addKeyValue("requestId", requestId)
274
.addKeyValue("duration", duration)
275
.log("Request completed");
276
277
// Multiple arguments in log call
278
logger.atInfo()
279
.addKeyValue("operation", "data_sync")
280
.log("Synchronized {} records in {} ms", recordCount, duration);
281
```
282
283
## Advanced Fluent Logging Patterns
284
285
### Conditional Logging with Context
286
287
```java
288
// Only log if specific conditions are met
289
if (logger.isDebugEnabled()) {
290
logger.atDebug()
291
.addKeyValue("threadName", Thread.currentThread().getName())
292
.addKeyValue("memoryUsage", Runtime.getRuntime().totalMemory())
293
.addKeyValue("activeConnections", connectionPool.getActiveCount())
294
.setMessage("System state snapshot")
295
.log();
296
}
297
```
298
299
### Business Event Logging
300
301
```java
302
// Order processing event
303
logger.atInfo()
304
.addMarker(MarkerFactory.getMarker("BUSINESS_EVENT"))
305
.setMessage("Order processed")
306
.addKeyValue("orderId", order.getId())
307
.addKeyValue("customerId", order.getCustomerId())
308
.addKeyValue("amount", order.getTotalAmount())
309
.addKeyValue("currency", order.getCurrency())
310
.addKeyValue("items", order.getItems().size())
311
.addKeyValue("processingTime", processingTime)
312
.addKeyValue("paymentMethod", order.getPaymentMethod())
313
.log();
314
```
315
316
### Error Context Enrichment
317
318
```java
319
// Rich error context
320
logger.atError()
321
.addMarker(MarkerFactory.getMarker("PAYMENT_ERROR"))
322
.setCause(paymentException)
323
.setMessage("Payment processing failed")
324
.addKeyValue("transactionId", transactionId)
325
.addKeyValue("amount", paymentAmount)
326
.addKeyValue("currency", currency)
327
.addKeyValue("paymentProvider", provider)
328
.addKeyValue("customerId", customerId)
329
.addKeyValue("retryAttempt", retryCount)
330
.addKeyValue("errorCode", paymentException.getErrorCode())
331
.log();
332
```
333
334
### Performance Monitoring
335
336
```java
337
// Performance event with timing
338
long startTime = System.currentTimeMillis();
339
try {
340
// perform operation
341
performDatabaseOperation();
342
343
logger.atInfo()
344
.addMarker(MarkerFactory.getMarker("PERFORMANCE"))
345
.setMessage("Database operation completed")
346
.addKeyValue("operation", "select")
347
.addKeyValue("table", "users")
348
.addKeyValue("duration", System.currentTimeMillis() - startTime)
349
.addKeyValue("recordCount", resultCount)
350
.log();
351
} catch (Exception e) {
352
logger.atError()
353
.addMarker(MarkerFactory.getMarker("PERFORMANCE"))
354
.setCause(e)
355
.setMessage("Database operation failed")
356
.addKeyValue("operation", "select")
357
.addKeyValue("table", "users")
358
.addKeyValue("duration", System.currentTimeMillis() - startTime)
359
.log();
360
}
361
```
362
363
### Lazy Evaluation Benefits
364
365
```java
366
// Expensive operations only executed if logging level is enabled
367
logger.atDebug()
368
.setMessage(() -> "Complex state: " + generateComplexStateDescription())
369
.addKeyValue("timestamp", () -> Instant.now().toString())
370
.addKeyValue("threadDump", () -> generateThreadDump())
371
.addKeyValue("memoryStats", () -> getDetailedMemoryStats())
372
.log();
373
```
374
375
### Caller Boundary Control
376
377
For advanced framework integration, control the caller boundary for accurate location information.
378
379
```java { .api }
380
/**
381
* Set the caller boundary for accurate location information
382
* @param fqcn Fully qualified class name of the caller boundary
383
*/
384
void setCallerBoundary(String fqcn);
385
```
386
387
**Usage Example:**
388
389
```java
390
import org.slf4j.Logger;
391
import org.slf4j.spi.CallerBoundaryAware;
392
import org.slf4j.spi.LoggingEventBuilder;
393
import java.util.Map;
394
395
// Framework wrapper example
396
public class LoggingWrapper {
397
private static final String FQCN = LoggingWrapper.class.getName();
398
private final Logger logger;
399
400
public void logBusinessEvent(String event, Map<String, Object> context) {
401
LoggingEventBuilder builder = logger.atInfo();
402
403
if (builder instanceof CallerBoundaryAware) {
404
((CallerBoundaryAware) builder).setCallerBoundary(FQCN);
405
}
406
407
builder.setMessage(event);
408
context.forEach(builder::addKeyValue);
409
builder.log();
410
}
411
}
412
```
413
414
## Integration with Observability Platforms
415
416
The structured key-value pairs integrate seamlessly with modern observability platforms:
417
418
```java
419
// APM/Observability friendly logging
420
logger.atInfo()
421
.addKeyValue("trace.id", traceId)
422
.addKeyValue("span.id", spanId)
423
.addKeyValue("service.name", "user-service")
424
.addKeyValue("service.version", "1.2.3")
425
.addKeyValue("environment", "production")
426
.setMessage("Service operation completed")
427
.log();
428
```