0
# Markers
1
2
Markers are named objects used to enrich log statements with categorical information. They enable logging frameworks to filter, route, or specially handle log messages based on marker content. Markers can contain references to other markers and are fully supported in both traditional and fluent logging APIs.
3
4
## Capabilities
5
6
### Marker Factory
7
8
Static factory for creating and retrieving Marker instances.
9
10
```java { .api }
11
/**
12
* MarkerFactory is a utility class producing Marker instances
13
*/
14
public class MarkerFactory {
15
/**
16
* Return a Marker instance as specified by the name parameter
17
* @param name The name of the Marker object to return
18
* @return marker instance
19
*/
20
public static Marker getMarker(String name);
21
22
/**
23
* Create a marker which is detached (even at birth) from the MarkerFactory
24
* @param name the name of the marker
25
* @return a dangling marker
26
*/
27
public static Marker getDetachedMarker(String name);
28
29
/**
30
* Return the IMarkerFactory instance in use
31
* @return the IMarkerFactory instance in use
32
*/
33
public static IMarkerFactory getIMarkerFactory();
34
}
35
```
36
37
### Marker Interface
38
39
Core marker interface for creating named categorical objects.
40
41
```java { .api }
42
/**
43
* Markers are named objects used to enrich log statements
44
*/
45
public interface Marker extends Serializable {
46
/**
47
* This constant represents any marker, including a null marker
48
*/
49
String ANY_MARKER = "*";
50
51
/**
52
* This constant represents any non-null marker
53
*/
54
String ANY_NON_NULL_MARKER = "+";
55
56
/**
57
* Get the name of this Marker
58
* @return name of marker
59
*/
60
String getName();
61
62
/**
63
* Add a reference to another Marker
64
* @param reference a reference to another marker
65
* @throws IllegalArgumentException if 'reference' is null
66
*/
67
void add(Marker reference);
68
69
/**
70
* Remove a marker reference
71
* @param reference the marker reference to remove
72
* @return true if reference could be found and removed, false otherwise
73
*/
74
boolean remove(Marker reference);
75
76
/**
77
* Does this marker have any references?
78
* @return true if this marker has one or more references, false otherwise
79
*/
80
boolean hasReferences();
81
82
/**
83
* Returns an Iterator which can be used to iterate over the references of this marker
84
* @return Iterator over the references of this marker
85
*/
86
Iterator<Marker> iterator();
87
88
/**
89
* Does this marker contain a reference to the 'other' marker?
90
* @param other The marker to test for inclusion
91
* @return Whether this marker contains the other marker
92
* @throws IllegalArgumentException if 'other' is null
93
*/
94
boolean contains(Marker other);
95
96
/**
97
* Does this marker contain the marker named 'name'?
98
* @param name The marker name to test for inclusion
99
* @return Whether this marker contains the other marker
100
*/
101
boolean contains(String name);
102
103
/**
104
* Markers are considered equal if they have the same name
105
* @param o object to compare
106
* @return true, if this.name equals o.name
107
*/
108
boolean equals(Object o);
109
110
/**
111
* Compute the hash code based on the name of this marker
112
* @return the computed hashCode
113
*/
114
int hashCode();
115
}
116
```
117
118
### Marker Factory Interface
119
120
Factory interface for creating and managing Marker instances.
121
122
```java { .api }
123
/**
124
* Factory interface for Marker instances
125
*/
126
public interface IMarkerFactory {
127
/**
128
* Manufacture a Marker instance by name. If the instance has been created earlier, return the previously created instance
129
* @param name the name of the marker to be created, null value is not allowed
130
* @return a Marker instance
131
*/
132
Marker getMarker(String name);
133
134
/**
135
* Checks if the marker with the name already exists
136
* @param name marker name
137
* @return true if the marker exists, false otherwise
138
*/
139
boolean exists(String name);
140
141
/**
142
* Detach an existing marker
143
* @param name The name of the marker to detach
144
* @return whether the marker could be detached or not
145
*/
146
boolean detachMarker(String name);
147
148
/**
149
* Create a marker which is detached from this IMarkerFactory
150
* @param name marker name
151
* @return a marker detached from this factory
152
*/
153
Marker getDetachedMarker(String name);
154
}
155
```
156
157
**Usage Examples:**
158
159
```java
160
import org.slf4j.Logger;
161
import org.slf4j.LoggerFactory;
162
import org.slf4j.Marker;
163
import org.slf4j.MarkerFactory;
164
165
public class MarkerExample {
166
private static final Logger logger = LoggerFactory.getLogger(MarkerExample.class);
167
168
// Create markers for different categories
169
private static final Marker SECURITY_MARKER = MarkerFactory.getMarker("SECURITY");
170
private static final Marker AUDIT_MARKER = MarkerFactory.getMarker("AUDIT");
171
private static final Marker PERFORMANCE_MARKER = MarkerFactory.getMarker("PERFORMANCE");
172
173
public void basicMarkerUsage() {
174
// Simple marker usage
175
logger.info(SECURITY_MARKER, "User authentication successful");
176
logger.warn(AUDIT_MARKER, "Configuration changed by admin user");
177
logger.debug(PERFORMANCE_MARKER, "Query execution time: {} ms", 150);
178
}
179
180
public void markerHierarchy() {
181
// Create nested markers
182
Marker securityMarker = MarkerFactory.getMarker("SECURITY");
183
Marker authMarker = MarkerFactory.getMarker("AUTH");
184
Marker loginMarker = MarkerFactory.getMarker("LOGIN");
185
186
// Build marker hierarchy: SECURITY -> AUTH -> LOGIN
187
authMarker.add(securityMarker);
188
loginMarker.add(authMarker);
189
190
// This log statement will match filters for LOGIN, AUTH, or SECURITY
191
logger.info(loginMarker, "User login attempt from IP: {}", "192.168.1.100");
192
193
// Check marker relationships
194
if (loginMarker.contains(securityMarker)) {
195
logger.debug("Login marker contains security marker");
196
}
197
}
198
199
public void conditionalLogging() {
200
// Check if marker-specific logging is enabled
201
if (logger.isInfoEnabled(AUDIT_MARKER)) {
202
// Perform expensive audit data collection only if needed
203
String auditData = collectAuditInformation();
204
logger.info(AUDIT_MARKER, "Audit event: {}", auditData);
205
}
206
}
207
}
208
```
209
210
### Traditional API with Markers
211
212
All traditional logging methods have marker-aware equivalents:
213
214
```java { .api }
215
// Marker-aware logging methods for each level
216
public interface Logger {
217
// TRACE level with markers
218
boolean isTraceEnabled(Marker marker);
219
void trace(Marker marker, String msg);
220
void trace(Marker marker, String format, Object arg);
221
void trace(Marker marker, String format, Object arg1, Object arg2);
222
void trace(Marker marker, String format, Object... arguments);
223
void trace(Marker marker, String msg, Throwable t);
224
225
// DEBUG level with markers
226
boolean isDebugEnabled(Marker marker);
227
void debug(Marker marker, String msg);
228
void debug(Marker marker, String format, Object arg);
229
void debug(Marker marker, String format, Object arg1, Object arg2);
230
void debug(Marker marker, String format, Object... arguments);
231
void debug(Marker marker, String msg, Throwable t);
232
233
// INFO level with markers
234
boolean isInfoEnabled(Marker marker);
235
void info(Marker marker, String msg);
236
void info(Marker marker, String format, Object arg);
237
void info(Marker marker, String format, Object arg1, Object arg2);
238
void info(Marker marker, String format, Object... arguments);
239
void info(Marker marker, String msg, Throwable t);
240
241
// WARN level with markers
242
boolean isWarnEnabled(Marker marker);
243
void warn(Marker marker, String msg);
244
void warn(Marker marker, String format, Object arg);
245
void warn(Marker marker, String format, Object arg1, Object arg2);
246
void warn(Marker marker, String format, Object... arguments);
247
void warn(Marker marker, String msg, Throwable t);
248
249
// ERROR level with markers
250
boolean isErrorEnabled(Marker marker);
251
void error(Marker marker, String msg);
252
void error(Marker marker, String format, Object arg);
253
void error(Marker marker, String format, Object arg1, Object arg2);
254
void error(Marker marker, String format, Object... arguments);
255
void error(Marker marker, String msg, Throwable t);
256
}
257
```
258
259
### Fluent API with Markers
260
261
The fluent API supports multiple markers on a single log statement:
262
263
```java
264
// Multiple markers with fluent API
265
logger.atWarn()
266
.addMarker(SECURITY_MARKER)
267
.addMarker(AUDIT_MARKER)
268
.addKeyValue("userId", "user123")
269
.addKeyValue("action", "sensitive_operation")
270
.log("Security violation detected");
271
272
// Conditional marker addition
273
LoggingEventBuilder builder = logger.atInfo();
274
if (isSecurityEvent) {
275
builder.addMarker(SECURITY_MARKER);
276
}
277
if (isAuditRequired) {
278
builder.addMarker(AUDIT_MARKER);
279
}
280
builder.log("Event processed successfully");
281
```
282
283
## Common Marker Patterns
284
285
### Categorization Markers
286
287
```java
288
// Functional category markers
289
private static final Marker DATABASE = MarkerFactory.getMarker("DATABASE");
290
private static final Marker HTTP = MarkerFactory.getMarker("HTTP");
291
private static final Marker CACHE = MarkerFactory.getMarker("CACHE");
292
293
// Operational category markers
294
private static final Marker STARTUP = MarkerFactory.getMarker("STARTUP");
295
private static final Marker SHUTDOWN = MarkerFactory.getMarker("SHUTDOWN");
296
private static final Marker HEALTH_CHECK = MarkerFactory.getMarker("HEALTH_CHECK");
297
298
public void databaseOperation() {
299
logger.debug(DATABASE, "Executing query: {}", sql);
300
logger.info(DATABASE, "Query completed in {} ms", duration);
301
}
302
303
public void httpRequest() {
304
logger.info(HTTP, "Incoming request: {} {}", method, path);
305
logger.debug(HTTP, "Request headers: {}", headers);
306
}
307
```
308
309
### Hierarchical Markers
310
311
```java
312
// Create marker hierarchy for better filtering
313
Marker applicationMarker = MarkerFactory.getMarker("APP");
314
Marker businessMarker = MarkerFactory.getMarker("BUSINESS");
315
Marker orderMarker = MarkerFactory.getMarker("ORDER");
316
Marker paymentMarker = MarkerFactory.getMarker("PAYMENT");
317
318
// Build hierarchy: APP -> BUSINESS -> ORDER/PAYMENT
319
businessMarker.add(applicationMarker);
320
orderMarker.add(businessMarker);
321
paymentMarker.add(businessMarker);
322
323
// Usage allows filtering at any level
324
logger.info(orderMarker, "Order {} created", orderId);
325
logger.warn(paymentMarker, "Payment {} failed", paymentId, exception);
326
327
// Filters can match:
328
// - Specific: only ORDER events
329
// - Category: all BUSINESS events (includes ORDER and PAYMENT)
330
// - Application: all APP events (includes everything)
331
```
332
333
### Security and Audit Markers
334
335
```java
336
// Security-related markers
337
private static final Marker SECURITY = MarkerFactory.getMarker("SECURITY");
338
private static final Marker AUTHENTICATION = MarkerFactory.getMarker("AUTH");
339
private static final Marker AUTHORIZATION = MarkerFactory.getMarker("AUTHZ");
340
private static final Marker SENSITIVE_DATA = MarkerFactory.getMarker("SENSITIVE");
341
342
// Create relationships
343
AUTHENTICATION.add(SECURITY);
344
AUTHORIZATION.add(SECURITY);
345
346
public void authenticateUser(String username, String password) {
347
logger.info(AUTHENTICATION, "Authentication attempt for user: {}", username);
348
349
try {
350
User user = authService.authenticate(username, password);
351
logger.info(AUTHENTICATION, "Authentication successful for user: {}", username);
352
} catch (AuthenticationException e) {
353
logger.warn(AUTHENTICATION, "Authentication failed for user: {}", username, e);
354
}
355
}
356
357
public void accessSensitiveData(String userId, String resource) {
358
if (!authService.hasPermission(userId, resource)) {
359
logger.warn(AUTHORIZATION, "Access denied: user {} attempted to access {}", userId, resource);
360
return;
361
}
362
363
logger.info(SENSITIVE_DATA, "Sensitive data accessed: user={}, resource={}", userId, resource);
364
}
365
```
366
367
### Performance Monitoring Markers
368
369
```java
370
private static final Marker PERFORMANCE = MarkerFactory.getMarker("PERFORMANCE");
371
private static final Marker SLOW_QUERY = MarkerFactory.getMarker("SLOW_QUERY");
372
private static final Marker MEMORY_WARNING = MarkerFactory.getMarker("MEMORY_WARNING");
373
374
SLOW_QUERY.add(PERFORMANCE);
375
MEMORY_WARNING.add(PERFORMANCE);
376
377
public void monitorQueryPerformance(String query, long executionTime) {
378
if (executionTime > SLOW_QUERY_THRESHOLD) {
379
logger.warn(SLOW_QUERY, "Slow query detected: {} ms - {}", executionTime, query);
380
} else {
381
logger.debug(PERFORMANCE, "Query executed in {} ms", executionTime);
382
}
383
}
384
385
public void checkMemoryUsage() {
386
long freeMemory = Runtime.getRuntime().freeMemory();
387
long totalMemory = Runtime.getRuntime().totalMemory();
388
double usagePercent = (double) (totalMemory - freeMemory) / totalMemory * 100;
389
390
if (usagePercent > 90) {
391
logger.warn(MEMORY_WARNING, "High memory usage: {:.1f}%", usagePercent);
392
} else {
393
logger.debug(PERFORMANCE, "Memory usage: {:.1f}%", usagePercent);
394
}
395
}
396
```
397
398
## Marker Management
399
400
### Singleton Pattern
401
402
Markers are typically managed as singletons within the MarkerFactory:
403
404
```java
405
// Multiple calls return the same instance
406
Marker marker1 = MarkerFactory.getMarker("TEST");
407
Marker marker2 = MarkerFactory.getMarker("TEST");
408
assert marker1 == marker2; // Same instance
409
410
// Detached markers are independent
411
Marker detached1 = MarkerFactory.getDetachedMarker("TEST");
412
Marker detached2 = MarkerFactory.getDetachedMarker("TEST");
413
assert detached1 != detached2; // Different instances
414
```
415
416
### Best Practices
417
418
1. **Static Final Constants**: Define markers as static final constants for reuse
419
2. **Descriptive Names**: Use clear, descriptive names that indicate purpose
420
3. **Hierarchical Organization**: Build marker hierarchies for flexible filtering
421
4. **Documentation**: Document marker semantics and intended use
422
5. **Consistent Naming**: Use consistent naming conventions across the application
423
424
```java
425
public class ApplicationMarkers {
426
// Base application marker
427
public static final Marker APP = MarkerFactory.getMarker("APP");
428
429
// Functional area markers
430
public static final Marker SECURITY = MarkerFactory.getMarker("SECURITY");
431
public static final Marker BUSINESS = MarkerFactory.getMarker("BUSINESS");
432
public static final Marker INTEGRATION = MarkerFactory.getMarker("INTEGRATION");
433
434
// Specific operation markers
435
public static final Marker USER_MANAGEMENT = MarkerFactory.getMarker("USER_MGMT");
436
public static final Marker ORDER_PROCESSING = MarkerFactory.getMarker("ORDER_PROC");
437
public static final Marker EXTERNAL_API = MarkerFactory.getMarker("EXT_API");
438
439
static {
440
// Build hierarchy
441
SECURITY.add(APP);
442
BUSINESS.add(APP);
443
INTEGRATION.add(APP);
444
445
USER_MANAGEMENT.add(SECURITY);
446
ORDER_PROCESSING.add(BUSINESS);
447
EXTERNAL_API.add(INTEGRATION);
448
}
449
}
450
```