0
# Logging & Diagnostics
1
2
Comprehensive logging infrastructure with structured logging support and application failure analysis capabilities.
3
4
## Capabilities
5
6
### Logging System Management
7
8
Core logging system abstraction and management.
9
10
```java { .api }
11
/**
12
* Common abstraction over logging systems
13
*/
14
public abstract class LoggingSystem {
15
/**
16
* System property used to override the system type
17
*/
18
public static final String SYSTEM_PROPERTY = LoggingSystem.class.getName();
19
20
/**
21
* Get the logging system for the given class loader
22
* @param classLoader the class loader or null to use the default
23
* @return the logging system
24
*/
25
public static LoggingSystem get(ClassLoader classLoader);
26
27
/**
28
* Detect and return the logging system in use
29
* @param classLoader the class loader or null to use the default
30
* @return the logging system or NONE if not detected
31
*/
32
public static LoggingSystem getLoggingSystem(ClassLoader classLoader);
33
34
/**
35
* Called before the logging system is initialized
36
*/
37
public abstract void beforeInitialize();
38
39
/**
40
* Fully initialize the logging system
41
* @param initializationContext the initialization context
42
* @param configLocation the config location or null if default
43
* @param logFile the log file or null if none
44
*/
45
public abstract void initialize(LoggingInitializationContext initializationContext,
46
String configLocation, LogFile logFile);
47
48
/**
49
* Clean up the logging system. The default implementation does nothing
50
*/
51
public abstract void cleanUp();
52
53
/**
54
* Returns a Runnable that can handle shutdown of this logging system when the JVM exits
55
* @return the shutdown handler or null
56
*/
57
public Runnable getShutdownHandler();
58
59
/**
60
* Set the log level for the specified logger
61
* @param loggerName the name of the logger to set
62
* @param level the log level
63
*/
64
public abstract void setLogLevel(String loggerName, LogLevel level);
65
66
/**
67
* Return the configurations that were applied when the logging system was initialized
68
* @return the configurations or an empty list
69
*/
70
public List<LoggingSystemProperty> getLoggingSystemProperties();
71
}
72
73
/**
74
* Logging levels supported by a LoggingSystem
75
*/
76
public enum LogLevel {
77
TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
78
}
79
80
/**
81
* A reference to a log file
82
*/
83
public class LogFile {
84
/**
85
* The name of the Spring property that contains the name of the log file
86
*/
87
public static final String FILE_NAME_PROPERTY = "logging.file.name";
88
89
/**
90
* The name of the Spring property that contains the directory where log files are written
91
*/
92
public static final String FILE_PATH_PROPERTY = "logging.file.path";
93
94
/**
95
* Create a new LogFile instance
96
* @param file the file reference (may be null)
97
* @param path the file path reference (may be null)
98
*/
99
public LogFile(String file, String path);
100
101
/**
102
* Get a LogFile from the given Spring Environment
103
* @param propertyResolver property resolver used to obtain the logging properties
104
* @return a LogFile instance or null if the Environment contains no log file configuration
105
*/
106
public static LogFile get(PropertyResolver propertyResolver);
107
108
/**
109
* Return the log file that will be written (this may not exist)
110
* @return the file or null if none
111
*/
112
public String toString();
113
}
114
115
/**
116
* Context passed to the LoggingSystem during initialization
117
*/
118
public class LoggingInitializationContext {
119
/**
120
* Create a new LoggingInitializationContext instance
121
* @param environment the Spring environment
122
*/
123
public LoggingInitializationContext(ConfigurableEnvironment environment);
124
125
/**
126
* Return the Spring environment that should be used for initialization
127
* @return the environment
128
*/
129
public ConfigurableEnvironment getEnvironment();
130
}
131
```
132
133
### Structured Logging
134
135
Support for structured logging formats and formatters.
136
137
```java { .api }
138
/**
139
* A formatter for structured log events
140
*/
141
@FunctionalInterface
142
public interface StructuredLogFormatter<E> {
143
/**
144
* Format the given log event
145
* @param event the log event to format
146
* @return the formatted log event
147
*/
148
String format(E event);
149
}
150
151
/**
152
* Common structured log formats
153
*/
154
public enum CommonStructuredLogFormat implements StructuredLogFormatter<ILoggingEvent> {
155
/**
156
* Elastic Common Schema format
157
*/
158
ECS {
159
@Override
160
public String format(ILoggingEvent event) {
161
return new EcsJsonFormatter().format(event);
162
}
163
},
164
165
/**
166
* Logstash JSON format
167
*/
168
LOGSTASH {
169
@Override
170
public String format(ILoggingEvent event) {
171
return new LogstashJsonFormatter().format(event);
172
}
173
};
174
175
/**
176
* Get the StructuredLogFormatter for the given format name
177
* @param format the format name
178
* @return the formatter or null if not found
179
*/
180
public static StructuredLogFormatter<ILoggingEvent> of(String format);
181
}
182
183
/**
184
* Factory for creating StructuredLogFormatter instances
185
*/
186
public interface StructuredLogFormatterFactory<E> {
187
/**
188
* Create a StructuredLogFormatter
189
* @param format the format string
190
* @return the formatter
191
*/
192
StructuredLogFormatter<E> createFormatter(String format);
193
}
194
```
195
196
### Failure Analysis
197
198
System for analyzing application startup failures and providing helpful diagnostics.
199
200
```java { .api }
201
/**
202
* Interface used to analyze failures and provide diagnostic information that can be displayed to the user
203
*/
204
@FunctionalInterface
205
public interface FailureAnalyzer {
206
/**
207
* Returns an analysis of the given failure, or null if no analysis was possible
208
* @param failure the failure
209
* @return the analysis or null
210
*/
211
FailureAnalysis analyze(Throwable failure);
212
}
213
214
/**
215
* Abstract base class for most FailureAnalyzer implementations
216
*/
217
public abstract class AbstractFailureAnalyzer<T extends Throwable> implements FailureAnalyzer {
218
@Override
219
public FailureAnalysis analyze(Throwable failure);
220
221
/**
222
* Returns an analysis of the given root failure, or null if no analysis was possible
223
* @param rootFailure the root failure passed to the analyzer
224
* @param cause the actual found cause
225
* @return the analysis or null
226
*/
227
protected abstract FailureAnalysis analyze(Throwable rootFailure, T cause);
228
229
/**
230
* Return the cause of the specified type that is at the root of the failure, or null if none is found
231
* @param failure the source failure
232
* @return the cause or null
233
*/
234
@SuppressWarnings("unchecked")
235
protected final T findCause(Throwable failure);
236
}
237
238
/**
239
* The result of analyzing a failure
240
*/
241
public class FailureAnalysis {
242
private final String description;
243
private final String action;
244
private final Throwable cause;
245
246
/**
247
* Creates a new FailureAnalysis with the given description and action
248
* @param description the description
249
* @param action the action
250
* @param cause the cause
251
*/
252
public FailureAnalysis(String description, String action, Throwable cause);
253
254
/**
255
* Returns a description of the failure
256
* @return the description
257
*/
258
public String getDescription();
259
260
/**
261
* Returns the action that the user should take to address the failure
262
* @return the action
263
*/
264
public String getAction();
265
266
/**
267
* Returns the cause of the failure
268
* @return the cause
269
*/
270
public Throwable getCause();
271
}
272
273
/**
274
* Reports FailureAnalysis instances to the user
275
*/
276
@FunctionalInterface
277
public interface FailureAnalysisReporter {
278
/**
279
* Report the specified failure analysis to the user
280
* @param analysis the analysis
281
*/
282
void report(FailureAnalysis analysis);
283
}
284
```
285
286
**Usage Examples:**
287
288
```java
289
// Custom failure analyzer
290
@Component
291
public class DatabaseConnectionFailureAnalyzer extends AbstractFailureAnalyzer<SQLException> {
292
293
@Override
294
protected FailureAnalysis analyze(Throwable rootFailure, SQLException cause) {
295
return new FailureAnalysis(
296
"Failed to connect to the database: " + cause.getMessage(),
297
"Check your database connection settings in application.properties",
298
cause
299
);
300
}
301
}
302
303
// Custom logging configuration
304
@Configuration
305
public class LoggingConfig {
306
307
@Bean
308
public LoggingSystemProperty customLoggingProperty() {
309
return LoggingSystemProperty.of("logging.custom.enabled", "true");
310
}
311
312
@EventListener
313
public void handleContextRefresh(ContextRefreshedEvent event) {
314
LoggingSystem loggingSystem = LoggingSystem.get(getClass().getClassLoader());
315
loggingSystem.setLogLevel("com.example", LogLevel.DEBUG);
316
}
317
}
318
```
319
320
### Application Information
321
322
Support for exposing build and version information.
323
324
```java { .api }
325
/**
326
* Provide build-related information such as group and artifact
327
*/
328
@ConfigurationProperties("spring.info.build")
329
public class BuildProperties extends InfoProperties {
330
/**
331
* Create an instance with the specified entries
332
* @param entries the entries
333
*/
334
public BuildProperties(Properties entries);
335
336
/**
337
* Get the application group
338
* @return the group or null
339
*/
340
public String getGroup();
341
342
/**
343
* Get the application artifact
344
* @return the artifact or null
345
*/
346
public String getArtifact();
347
348
/**
349
* Get the application name
350
* @return the name or null
351
*/
352
public String getName();
353
354
/**
355
* Get the application version
356
* @return the version or null
357
*/
358
public String getVersion();
359
360
/**
361
* Get the timestamp of when the application was built
362
* @return the build time or null
363
*/
364
public Instant getTime();
365
}
366
367
/**
368
* Provide Git-related information
369
*/
370
@ConfigurationProperties("spring.info.git")
371
public class GitProperties extends InfoProperties {
372
/**
373
* Create an instance with the specified entries
374
* @param entries the entries
375
*/
376
public GitProperties(Properties entries);
377
378
/**
379
* Get the name of the branch
380
* @return the branch or null
381
*/
382
public String getBranch();
383
384
/**
385
* Get the commit id
386
* @return the commit id or null
387
*/
388
public String getCommitId();
389
390
/**
391
* Get the abbreviated commit id
392
* @return the short commit id or null
393
*/
394
public String getShortCommitId();
395
396
/**
397
* Get the commit time
398
* @return the commit time or null
399
*/
400
public Instant getCommitTime();
401
}
402
403
/**
404
* Base class for configuration properties that provide application information
405
*/
406
public abstract class InfoProperties implements Iterable<InfoProperties.Entry> {
407
private final Properties entries;
408
409
/**
410
* Create an instance with the specified entries
411
* @param entries the entries
412
*/
413
public InfoProperties(Properties entries);
414
415
/**
416
* Return the value of the specified property or null if the property is not set
417
* @param key the key of the property
418
* @return the property value or null
419
*/
420
public String get(String key);
421
422
/**
423
* Return the value of the specified property as an Instant or null if the property is not set or cannot be converted
424
* @param key the key of the property
425
* @return the property value or null
426
*/
427
public Instant getInstant(String key);
428
429
@Override
430
public Iterator<Entry> iterator();
431
432
/**
433
* A key/value pair entry from the info
434
*/
435
public static final class Entry {
436
private final String key;
437
private final String value;
438
439
/**
440
* Create a new Entry instance
441
* @param key the entry key
442
* @param value the entry value
443
*/
444
public Entry(String key, String value);
445
446
/**
447
* Return the key of the entry
448
* @return the key
449
*/
450
public String getKey();
451
452
/**
453
* Return the value of the entry
454
* @return the value
455
*/
456
public String getValue();
457
}
458
}
459
```
460
461
### Logging Listeners and Events
462
463
Event-driven logging configuration and lifecycle management.
464
465
```java { .api }
466
/**
467
* ApplicationListener that configures the LoggingSystem
468
*/
469
public class LoggingApplicationListener implements GenericApplicationListener, Ordered {
470
/**
471
* Create a new LoggingApplicationListener instance
472
*/
473
public LoggingApplicationListener();
474
475
@Override
476
public void onApplicationEvent(ApplicationEvent event);
477
478
@Override
479
public boolean supportsEventType(ResolvableType resolvableType);
480
481
@Override
482
public int getOrder();
483
484
/**
485
* Set if initialization arguments should be parsed for debug and trace options
486
* @param parseArgs if arguments should be parsed
487
*/
488
public void setParseArgs(boolean parseArgs);
489
490
/**
491
* Set a custom logging system
492
* @param loggingSystem the logging system
493
*/
494
public void setLoggingSystem(LoggingSystem loggingSystem);
495
}
496
497
/**
498
* ClearTrigger that can be used to clear caches once the application context loads
499
*/
500
public class ClearCachesApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
501
@Override
502
public void onApplicationEvent(ContextRefreshedEvent event);
503
}
504
```
505
506
**Usage Examples:**
507
508
```java
509
// Build information configuration
510
@Configuration
511
public class InfoConfig {
512
513
@Bean
514
@ConditionalOnResource(resources = "META-INF/build-info.properties")
515
public BuildProperties buildProperties() throws IOException {
516
Properties properties = new Properties();
517
try (InputStream inputStream = getClass().getResourceAsStream("/META-INF/build-info.properties")) {
518
if (inputStream != null) {
519
properties.load(inputStream);
520
}
521
}
522
return new BuildProperties(properties);
523
}
524
525
@Bean
526
@ConditionalOnResource(resources = "git.properties")
527
public GitProperties gitProperties() throws IOException {
528
Properties properties = new Properties();
529
try (InputStream inputStream = getClass().getResourceAsStream("/git.properties")) {
530
if (inputStream != null) {
531
properties.load(inputStream);
532
}
533
}
534
return new GitProperties(properties);
535
}
536
}
537
538
// Using build and git information
539
@RestController
540
public class InfoController {
541
542
private final BuildProperties buildProperties;
543
private final GitProperties gitProperties;
544
545
public InfoController(BuildProperties buildProperties, GitProperties gitProperties) {
546
this.buildProperties = buildProperties;
547
this.gitProperties = gitProperties;
548
}
549
550
@GetMapping("/info")
551
public Map<String, Object> info() {
552
Map<String, Object> info = new HashMap<>();
553
554
if (buildProperties != null) {
555
info.put("app", Map.of(
556
"name", buildProperties.getName(),
557
"version", buildProperties.getVersion(),
558
"buildTime", buildProperties.getTime()
559
));
560
}
561
562
if (gitProperties != null) {
563
info.put("git", Map.of(
564
"branch", gitProperties.getBranch(),
565
"commit", gitProperties.getShortCommitId(),
566
"commitTime", gitProperties.getCommitTime()
567
));
568
}
569
570
return info;
571
}
572
}
573
574
// Structured logging configuration
575
@Configuration
576
public class StructuredLoggingConfig {
577
578
@Bean
579
@ConditionalOnProperty(name = "logging.structured.format", havingValue = "ecs")
580
public StructuredLogFormatter<ILoggingEvent> ecsFormatter() {
581
return CommonStructuredLogFormat.ECS;
582
}
583
584
@Bean
585
@ConditionalOnProperty(name = "logging.structured.format", havingValue = "logstash")
586
public StructuredLogFormatter<ILoggingEvent> logstashFormatter() {
587
return CommonStructuredLogFormat.LOGSTASH;
588
}
589
}
590
```