0
# Status & Error Handling
1
2
Internal status reporting system for Log4j configuration issues, initialization problems, and runtime diagnostics. Essential for troubleshooting logging setup.
3
4
## Capabilities
5
6
### StatusLogger
7
8
Internal logger for Log4j status messages and diagnostics.
9
10
```java { .api }
11
/**
12
* Logger for Log4j internal status messages
13
*/
14
public class StatusLogger implements Logger {
15
/** Get the status logger instance */
16
public static StatusLogger getLogger();
17
18
// Implements all Logger interface methods for internal status logging
19
@Override
20
public void trace(String message);
21
@Override
22
public void debug(String message);
23
@Override
24
public void info(String message);
25
@Override
26
public void warn(String message);
27
@Override
28
public void error(String message);
29
@Override
30
public void fatal(String message);
31
32
// Parameterized logging for status messages
33
@Override
34
public void info(String message, Object... params);
35
@Override
36
public void warn(String message, Object... params);
37
@Override
38
public void error(String message, Object... params);
39
40
// Level checking
41
@Override
42
public boolean isInfoEnabled();
43
@Override
44
public boolean isWarnEnabled();
45
@Override
46
public boolean isErrorEnabled();
47
@Override
48
public boolean isDebugEnabled();
49
@Override
50
public boolean isTraceEnabled();
51
52
// Status-specific methods
53
/** Add a status listener */
54
public void registerListener(StatusListener listener);
55
56
/** Remove a status listener */
57
public void removeListener(StatusListener listener);
58
59
/** Get all registered listeners */
60
public Iterable<StatusListener> getListeners();
61
62
/** Clear all listeners */
63
public void reset();
64
65
/** Get status data entries */
66
public List<StatusData> getStatusData();
67
68
/** Clear status data */
69
public void clear();
70
71
/** Set status logger level */
72
public void setLevel(Level level);
73
}
74
```
75
76
**Usage Examples:**
77
78
```java
79
public void demonstrateStatusLogger() {
80
// Get status logger instance
81
StatusLogger statusLogger = StatusLogger.getLogger();
82
83
// Status logger is used internally by Log4j, but can be accessed for diagnostics
84
statusLogger.info("Custom status message");
85
statusLogger.warn("Configuration issue detected");
86
statusLogger.error("Failed to initialize appender");
87
88
// Check status logger state
89
if (statusLogger.isDebugEnabled()) {
90
statusLogger.debug("Debug-level status information");
91
}
92
93
// Get historical status data
94
List<StatusData> statusHistory = statusLogger.getStatusData();
95
for (StatusData data : statusHistory) {
96
System.out.printf("[%s] %s - %s%n",
97
data.getLevel(),
98
new Date(data.getTimestamp()),
99
data.getMessage().getFormattedMessage());
100
}
101
102
// Clear status history
103
statusLogger.clear();
104
}
105
106
// Custom component that uses status logging
107
public class CustomAppender {
108
private static final StatusLogger STATUS_LOGGER = StatusLogger.getLogger();
109
110
public void initialize() {
111
STATUS_LOGGER.info("Initializing custom appender");
112
113
try {
114
// Initialization logic
115
setupResources();
116
STATUS_LOGGER.info("Custom appender initialized successfully");
117
} catch (Exception e) {
118
STATUS_LOGGER.error("Failed to initialize custom appender", e);
119
throw new RuntimeException("Appender initialization failed", e);
120
}
121
}
122
123
public void append(LogEvent event) {
124
try {
125
// Append logic
126
writeLogEvent(event);
127
} catch (Exception e) {
128
STATUS_LOGGER.error("Failed to append log event", e);
129
}
130
}
131
132
private void setupResources() {
133
// Resource setup
134
}
135
136
private void writeLogEvent(Object event) {
137
// Write logic
138
}
139
}
140
```
141
142
### StatusListener Interface
143
144
Interface for listening to Log4j internal status messages.
145
146
```java { .api }
147
/**
148
* Interface for listening to Log4j status messages
149
*/
150
public interface StatusListener {
151
/**
152
* Handle a status message
153
* @param data Status data containing level, message, timestamp, etc.
154
*/
155
void log(StatusData data);
156
157
/**
158
* Get the minimum level this listener wants to receive
159
* @return Minimum status level
160
*/
161
Level getStatusLevel();
162
163
/**
164
* Close/cleanup the listener
165
*/
166
void close() throws IOException;
167
}
168
```
169
170
**Usage Examples:**
171
172
```java
173
// Custom status listener implementation
174
public class CustomStatusListener implements StatusListener {
175
private final Level minimumLevel;
176
private final PrintWriter writer;
177
178
public CustomStatusListener(Level minimumLevel, String filename) throws IOException {
179
this.minimumLevel = minimumLevel;
180
this.writer = new PrintWriter(new FileWriter(filename, true));
181
}
182
183
@Override
184
public void log(StatusData data) {
185
// Only log if level is appropriate
186
if (data.getLevel().isMoreSpecificThan(minimumLevel)) {
187
writer.printf("[%s] %s [%s] %s - %s%n",
188
new Date(data.getTimestamp()),
189
data.getLevel(),
190
data.getThreadName(),
191
"StatusLogger",
192
data.getMessage().getFormattedMessage());
193
194
if (data.getThrowable() != null) {
195
data.getThrowable().printStackTrace(writer);
196
}
197
198
writer.flush();
199
}
200
}
201
202
@Override
203
public Level getStatusLevel() {
204
return minimumLevel;
205
}
206
207
@Override
208
public void close() throws IOException {
209
writer.close();
210
}
211
}
212
213
// Database status listener
214
public class DatabaseStatusListener implements StatusListener {
215
private final DataSource dataSource;
216
private final Level minimumLevel;
217
218
public DatabaseStatusListener(DataSource dataSource, Level minimumLevel) {
219
this.dataSource = dataSource;
220
this.minimumLevel = minimumLevel;
221
}
222
223
@Override
224
public void log(StatusData data) {
225
if (data.getLevel().isMoreSpecificThan(minimumLevel)) {
226
try (Connection conn = dataSource.getConnection();
227
PreparedStatement stmt = conn.prepareStatement(
228
"INSERT INTO log4j_status (timestamp, level, thread_name, message, throwable) VALUES (?, ?, ?, ?, ?)")) {
229
230
stmt.setTimestamp(1, new Timestamp(data.getTimestamp()));
231
stmt.setString(2, data.getLevel().toString());
232
stmt.setString(3, data.getThreadName());
233
stmt.setString(4, data.getMessage().getFormattedMessage());
234
235
if (data.getThrowable() != null) {
236
StringWriter sw = new StringWriter();
237
data.getThrowable().printStackTrace(new PrintWriter(sw));
238
stmt.setString(5, sw.toString());
239
} else {
240
stmt.setNull(5, Types.VARCHAR);
241
}
242
243
stmt.executeUpdate();
244
245
} catch (SQLException e) {
246
// Can't use StatusLogger here to avoid infinite recursion
247
System.err.println("Failed to log status to database: " + e.getMessage());
248
}
249
}
250
}
251
252
@Override
253
public Level getStatusLevel() {
254
return minimumLevel;
255
}
256
257
@Override
258
public void close() {
259
// Database connections are managed by DataSource
260
}
261
}
262
263
// Register and use status listeners
264
public class StatusListenerManagement {
265
266
public void setupStatusListeners() throws IOException {
267
StatusLogger statusLogger = StatusLogger.getLogger();
268
269
// File-based status listener
270
CustomStatusListener fileListener = new CustomStatusListener(Level.WARN, "log4j-status.log");
271
statusLogger.registerListener(fileListener);
272
273
// Console status listener for errors only
274
StatusListener consoleListener = new StatusListener() {
275
@Override
276
public void log(StatusData data) {
277
if (data.getLevel().isMoreSpecificThan(Level.ERROR)) {
278
System.err.printf("LOG4J ERROR: %s%n", data.getMessage().getFormattedMessage());
279
if (data.getThrowable() != null) {
280
data.getThrowable().printStackTrace(System.err);
281
}
282
}
283
}
284
285
@Override
286
public Level getStatusLevel() {
287
return Level.ERROR;
288
}
289
290
@Override
291
public void close() {
292
// Nothing to close
293
}
294
};
295
statusLogger.registerListener(consoleListener);
296
297
// Shutdown hook to clean up listeners
298
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
299
try {
300
fileListener.close();
301
} catch (IOException e) {
302
System.err.println("Error closing status listener: " + e.getMessage());
303
}
304
}));
305
}
306
}
307
```
308
309
### StatusConsoleListener
310
311
Built-in status listener that outputs to console/System.err.
312
313
```java { .api }
314
/**
315
* Built-in status listener that outputs to console
316
*/
317
public class StatusConsoleListener implements StatusListener {
318
/** Create listener with default level (ERROR) */
319
public StatusConsoleListener();
320
321
/** Create listener with specific level */
322
public StatusConsoleListener(Level level);
323
324
/** Create listener with specific level and target stream */
325
public StatusConsoleListener(Level level, PrintStream stream);
326
327
@Override
328
public void log(StatusData data);
329
330
@Override
331
public Level getStatusLevel();
332
333
@Override
334
public void close();
335
336
/** Set the target print stream */
337
public void setTarget(PrintStream target);
338
339
/** Get the target print stream */
340
public PrintStream getTarget();
341
}
342
```
343
344
**Usage Examples:**
345
346
```java
347
public void demonstrateStatusConsoleListener() {
348
StatusLogger statusLogger = StatusLogger.getLogger();
349
350
// Default console listener (ERROR level to System.err)
351
StatusConsoleListener defaultConsole = new StatusConsoleListener();
352
statusLogger.registerListener(defaultConsole);
353
354
// Console listener with custom level
355
StatusConsoleListener warnConsole = new StatusConsoleListener(Level.WARN);
356
statusLogger.registerListener(warnConsole);
357
358
// Console listener with custom stream
359
StatusConsoleListener customConsole = new StatusConsoleListener(Level.INFO, System.out);
360
statusLogger.registerListener(customConsole);
361
362
// Configure listener dynamically
363
customConsole.setTarget(System.err);
364
365
// Test status logging
366
statusLogger.info("This will appear on custom console listener");
367
statusLogger.warn("This will appear on both warn and default listeners");
368
statusLogger.error("This will appear on all listeners");
369
}
370
371
// Application startup with status console listener
372
public class ApplicationStartup {
373
374
public static void main(String[] args) {
375
// Set up status console listener early in application startup
376
StatusLogger statusLogger = StatusLogger.getLogger();
377
StatusConsoleListener consoleListener = new StatusConsoleListener(Level.WARN);
378
statusLogger.registerListener(consoleListener);
379
380
// Now any Log4j initialization issues will be visible
381
Logger appLogger = LogManager.getLogger(ApplicationStartup.class);
382
appLogger.info("Application starting...");
383
384
// Application logic...
385
}
386
}
387
```
388
389
### StatusData Interface
390
391
Interface representing individual status message data.
392
393
```java { .api }
394
/**
395
* Interface representing status message data
396
*/
397
public interface StatusData {
398
/** Get the timestamp when status was created */
399
long getTimestamp();
400
401
/** Get the status level */
402
Level getLevel();
403
404
/** Get the status message */
405
Message getMessage();
406
407
/** Get the thread name where status was created */
408
String getThreadName();
409
410
/** Get associated throwable if any */
411
Throwable getThrowable();
412
413
/** Get stack trace element where status was created */
414
StackTraceElement getStackTraceElement();
415
}
416
```
417
418
**Usage Examples:**
419
420
```java
421
public void demonstrateStatusData() {
422
StatusLogger statusLogger = StatusLogger.getLogger();
423
424
// Create a custom status listener to examine StatusData
425
StatusListener dataExaminer = new StatusListener() {
426
@Override
427
public void log(StatusData data) {
428
// Examine all aspects of status data
429
System.out.println("=== Status Data Analysis ===");
430
System.out.println("Timestamp: " + new Date(data.getTimestamp()));
431
System.out.println("Level: " + data.getLevel());
432
System.out.println("Thread: " + data.getThreadName());
433
System.out.println("Message: " + data.getMessage().getFormattedMessage());
434
435
if (data.getThrowable() != null) {
436
System.out.println("Exception: " + data.getThrowable().getClass().getSimpleName());
437
System.out.println("Exception Message: " + data.getThrowable().getMessage());
438
}
439
440
if (data.getStackTraceElement() != null) {
441
StackTraceElement ste = data.getStackTraceElement();
442
System.out.printf("Location: %s.%s(%s:%d)%n",
443
ste.getClassName(),
444
ste.getMethodName(),
445
ste.getFileName(),
446
ste.getLineNumber());
447
}
448
System.out.println("========================");
449
}
450
451
@Override
452
public Level getStatusLevel() {
453
return Level.DEBUG;
454
}
455
456
@Override
457
public void close() {
458
// Nothing to close
459
}
460
};
461
462
statusLogger.registerListener(dataExaminer);
463
464
// Generate some status messages to examine
465
statusLogger.info("Status info message");
466
statusLogger.warn("Status warning message");
467
statusLogger.error("Status error message", new RuntimeException("test exception"));
468
}
469
470
// Status data aggregator
471
public class StatusDataAggregator implements StatusListener {
472
private final Map<Level, AtomicInteger> levelCounts = new ConcurrentHashMap<>();
473
private final Map<String, AtomicInteger> threadCounts = new ConcurrentHashMap<>();
474
private final AtomicLong totalMessages = new AtomicLong();
475
476
@Override
477
public void log(StatusData data) {
478
totalMessages.incrementAndGet();
479
480
// Count by level
481
levelCounts.computeIfAbsent(data.getLevel(), k -> new AtomicInteger()).incrementAndGet();
482
483
// Count by thread
484
threadCounts.computeIfAbsent(data.getThreadName(), k -> new AtomicInteger()).incrementAndGet();
485
}
486
487
@Override
488
public Level getStatusLevel() {
489
return Level.TRACE; // Capture all levels
490
}
491
492
@Override
493
public void close() {
494
// Print summary
495
System.out.println("=== Status Data Summary ===");
496
System.out.println("Total Messages: " + totalMessages.get());
497
498
System.out.println("By Level:");
499
levelCounts.forEach((level, count) ->
500
System.out.println(" " + level + ": " + count.get()));
501
502
System.out.println("By Thread:");
503
threadCounts.forEach((thread, count) ->
504
System.out.println(" " + thread + ": " + count.get()));
505
}
506
507
public Map<Level, Integer> getLevelCounts() {
508
return levelCounts.entrySet().stream()
509
.collect(Collectors.toMap(
510
Map.Entry::getKey,
511
e -> e.getValue().get()));
512
}
513
514
public Map<String, Integer> getThreadCounts() {
515
return threadCounts.entrySet().stream()
516
.collect(Collectors.toMap(
517
Map.Entry::getKey,
518
e -> e.getValue().get()));
519
}
520
}
521
```
522
523
### Common Status Scenarios
524
525
Typical status messages and how to handle them for troubleshooting.
526
527
```java { .api }
528
// Common status scenarios and troubleshooting
529
public class StatusTroubleshooting {
530
private static final StatusLogger STATUS_LOGGER = StatusLogger.getLogger();
531
532
// Configuration file not found
533
public void handleConfigurationIssues() {
534
STATUS_LOGGER.error("Configuration file not found: {}", "log4j2.xml");
535
STATUS_LOGGER.warn("Using default configuration");
536
537
// Appender initialization failure
538
STATUS_LOGGER.error("Failed to initialize FileAppender", new IOException("Permission denied"));
539
540
// Plugin loading issues
541
STATUS_LOGGER.warn("Plugin class not found: {}", "com.example.CustomPlugin");
542
}
543
}
544
```
545
546
**Usage Examples:**
547
548
```java
549
// Comprehensive status monitoring setup
550
public class StatusMonitoringSetup {
551
552
public static void setupComprehensiveStatusMonitoring() {
553
StatusLogger statusLogger = StatusLogger.getLogger();
554
555
// Set status logger to capture all levels
556
statusLogger.setLevel(Level.TRACE);
557
558
// Multi-target status listener
559
StatusListener multiListener = new StatusListener() {
560
private final List<StatusListener> listeners = Arrays.asList(
561
new StatusConsoleListener(Level.ERROR, System.err),
562
createFileListener(),
563
createMetricsListener()
564
);
565
566
@Override
567
public void log(StatusData data) {
568
listeners.forEach(listener -> {
569
try {
570
if (data.getLevel().isMoreSpecificThan(listener.getStatusLevel())) {
571
listener.log(data);
572
}
573
} catch (Exception e) {
574
System.err.println("Error in status listener: " + e.getMessage());
575
}
576
});
577
}
578
579
@Override
580
public Level getStatusLevel() {
581
return Level.TRACE; // Accept all levels
582
}
583
584
@Override
585
public void close() throws IOException {
586
for (StatusListener listener : listeners) {
587
try {
588
listener.close();
589
} catch (IOException e) {
590
System.err.println("Error closing status listener: " + e.getMessage());
591
}
592
}
593
}
594
};
595
596
statusLogger.registerListener(multiListener);
597
598
// Shutdown hook for cleanup
599
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
600
try {
601
multiListener.close();
602
} catch (IOException e) {
603
System.err.println("Error during status listener cleanup: " + e.getMessage());
604
}
605
}));
606
}
607
608
private static StatusListener createFileListener() {
609
try {
610
return new CustomStatusListener(Level.WARN, "log4j-status.log");
611
} catch (IOException e) {
612
System.err.println("Failed to create file status listener: " + e.getMessage());
613
return new StatusConsoleListener(Level.WARN);
614
}
615
}
616
617
private static StatusListener createMetricsListener() {
618
return new StatusDataAggregator();
619
}
620
}
621
622
// Application with proper status monitoring
623
public class MonitoredApplication {
624
625
public static void main(String[] args) {
626
// Set up status monitoring before any Log4j usage
627
StatusMonitoringSetup.setupComprehensiveStatusMonitoring();
628
629
// Now initialize logging - any issues will be captured
630
Logger logger = LogManager.getLogger(MonitoredApplication.class);
631
632
logger.info("Application started with comprehensive status monitoring");
633
634
// Application logic...
635
636
// Check status at the end
637
StatusLogger.getLogger().getStatusData().forEach(data -> {
638
if (data.getLevel().isMoreSpecificThan(Level.WARN)) {
639
System.out.println("Warning/Error during execution: " +
640
data.getMessage().getFormattedMessage());
641
}
642
});
643
}
644
}
645
```