0
# Logger Adapters
1
2
The logger adapter system provides a pluggable architecture for bridging JUL Logger instances to different Log4j implementations. It automatically selects the most appropriate adapter based on available Log4j components and supports custom adapter implementations.
3
4
## Overview
5
6
Logger adapters bridge the gap between JUL's Logger interface and Log4j's logging infrastructure. The system provides:
7
8
- **Automatic Selection**: Chooses optimal adapter based on available Log4j components
9
- **Custom Override**: Supports custom adapter implementations via configuration
10
- **Context Management**: Handles LoggerContext lifecycle and isolation
11
- **Performance Optimization**: Minimizes overhead through efficient logger creation
12
13
## Adapter Hierarchy
14
15
```
16
AbstractLoggerAdapter (abstract base)
17
├── ApiLoggerAdapter (log4j-api only)
18
└── CoreLoggerAdapter (log4j-core available)
19
```
20
21
## Adapter Selection Process
22
23
The LogManager selects adapters in the following priority order:
24
25
1. **Custom Adapter**: If `log4j.jul.LoggerAdapter` property is set
26
2. **CoreLoggerAdapter**: If log4j-core is available on classpath
27
3. **ApiLoggerAdapter**: Fallback when only log4j-api is available
28
29
```java
30
// Selection logic
31
String customAdapterClass = PropertiesUtil.getProperties()
32
.getStringProperty(Constants.LOGGER_ADAPTOR_PROPERTY);
33
34
if (customAdapterClass != null) {
35
// Try to load custom adapter
36
adapter = LoaderUtil.newCheckedInstanceOf(customAdapterClass, AbstractLoggerAdapter.class);
37
} else {
38
// Default to ApiLoggerAdapter (CoreLoggerAdapter detection is automatic)
39
adapter = new ApiLoggerAdapter();
40
}
41
```
42
43
## Usage
44
45
### Automatic Selection
46
47
Most applications use automatic adapter selection:
48
49
```java
50
// Set LogManager - adapter selection is automatic
51
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
52
53
// Standard JUL usage - adapter works transparently
54
java.util.logging.Logger logger = java.util.logging.Logger.getLogger("com.example");
55
logger.info("Message logged through selected adapter");
56
```
57
58
### Custom Adapter Configuration
59
60
```java
61
// Configure custom adapter via system property
62
System.setProperty("log4j.jul.LoggerAdapter", "com.example.CustomLoggerAdapter");
63
64
// Or via log4j2.properties
65
// log4j.jul.LoggerAdapter=com.example.CustomLoggerAdapter
66
```
67
68
## API Reference
69
70
### AbstractLoggerAdapter
71
72
```java { .api }
73
public abstract class AbstractLoggerAdapter extends org.apache.logging.log4j.spi.AbstractLoggerAdapter<Logger> {
74
/**
75
* Gets the appropriate LoggerContext for the current execution context.
76
* Considers classloader dependency and caller class for context isolation.
77
*
78
* @return LoggerContext for creating loggers
79
*/
80
protected LoggerContext getContext();
81
82
/**
83
* Creates a new Logger instance for the given name and context.
84
* Implementation varies based on available Log4j components.
85
*
86
* @param name the logger name
87
* @param context the LoggerContext
88
* @return new Logger instance
89
*/
90
protected abstract Logger newLogger(String name, LoggerContext context);
91
}
92
```
93
94
### ApiLoggerAdapter
95
96
```java { .api }
97
public class ApiLoggerAdapter extends AbstractLoggerAdapter {
98
/**
99
* Creates ApiLogger instances using only log4j-api components.
100
* Uses MessageFormatMessageFactory for JUL-style message formatting.
101
*
102
* @param name the logger name
103
* @param context the LoggerContext
104
* @return new ApiLogger instance
105
*/
106
protected Logger newLogger(String name, LoggerContext context);
107
}
108
```
109
110
### CoreLoggerAdapter
111
112
```java { .api }
113
public class CoreLoggerAdapter extends AbstractLoggerAdapter {
114
/**
115
* Creates enhanced Logger instances when log4j-core is available.
116
* Returns CoreLogger for full functionality or ApiLogger as fallback.
117
*
118
* @param name the logger name
119
* @param context the LoggerContext
120
* @return new CoreLogger or ApiLogger instance
121
*/
122
protected Logger newLogger(String name, LoggerContext context);
123
}
124
```
125
126
## Logger Implementations
127
128
### ApiLogger
129
130
The ApiLogger provides JUL Logger implementation using only log4j-api:
131
132
```java
133
// Created by ApiLoggerAdapter
134
java.util.logging.Logger logger = java.util.logging.Logger.getLogger("example");
135
136
// Full JUL API support with some limitations
137
logger.info("Standard logging works");
138
logger.log(java.util.logging.Level.WARNING, "Parameterized message: {0}", value);
139
140
// Limitations due to log4j-api constraints
141
logger.setLevel(java.util.logging.Level.DEBUG); // Limited support
142
Logger parent = logger.getParent(); // May not be accurate
143
```
144
145
**ApiLogger Features:**
146
- Complete JUL Logger interface implementation
147
- Delegates to underlying Log4j ExtendedLogger
148
- MessageFormatMessageFactory for JUL-style parameter substitution
149
- Limited `setLevel()` and `getParent()` support due to API constraints
150
151
### CoreLogger
152
153
The CoreLogger provides enhanced functionality when log4j-core is available:
154
155
```java
156
// Created by CoreLoggerAdapter when log4j-core is present
157
java.util.logging.Logger logger = java.util.logging.Logger.getLogger("example");
158
159
// Enhanced functionality with full JUL API support
160
logger.setLevel(java.util.logging.Level.DEBUG); // Full support
161
Logger parent = logger.getParent(); // Accurate parent relationships
162
logger.setFilter(customFilter); // Full filter support
163
```
164
165
**CoreLogger Features:**
166
- Full JUL Logger interface implementation
167
- Complete level management support
168
- Accurate parent-child relationships
169
- Enhanced performance through log4j-core integration
170
171
## Context Management
172
173
### LoggerContext Selection
174
175
The adapter system handles LoggerContext selection based on:
176
177
1. **ClassLoader Dependency**: Uses appropriate context for classloader isolation
178
2. **Caller Context**: Determines caller class for context selection
179
3. **Factory Configuration**: Respects LoggerFactory configuration
180
181
```java
182
// Context selection logic in AbstractLoggerAdapter
183
protected LoggerContext getContext() {
184
return getContext(
185
LogManager.getFactory().isClassLoaderDependent()
186
? StackLocatorUtil.getCallerClass(java.util.logging.LogManager.class)
187
: null
188
);
189
}
190
```
191
192
### Context Isolation
193
194
Different contexts allow for:
195
- **Separate Configurations**: Each context can have independent log4j2.xml
196
- **ClassLoader Isolation**: Prevents configuration conflicts between applications
197
- **Resource Management**: Proper cleanup when contexts are destroyed
198
199
## Custom Adapter Implementation
200
201
Create custom adapters for specialized requirements:
202
203
```java
204
public class CustomLoggerAdapter extends AbstractLoggerAdapter {
205
206
@Override
207
protected Logger newLogger(String name, LoggerContext context) {
208
// Custom logger creation logic
209
ExtendedLogger log4jLogger = context.getLogger(name, customMessageFactory);
210
211
// Return custom logger implementation
212
return new CustomJulLogger(log4jLogger);
213
}
214
215
// Custom logger implementation
216
private static class CustomJulLogger extends java.util.logging.Logger {
217
private final ExtendedLogger delegate;
218
219
CustomJulLogger(ExtendedLogger delegate) {
220
super(delegate.getName(), null);
221
this.delegate = delegate;
222
}
223
224
@Override
225
public void info(String msg) {
226
// Custom logging behavior
227
delegate.info("[CUSTOM] " + msg);
228
}
229
230
// Implement other Logger methods...
231
}
232
}
233
```
234
235
### Custom Adapter Requirements
236
237
Custom adapters must:
238
- Extend `AbstractLoggerAdapter`
239
- Implement `newLogger(String, LoggerContext)` method
240
- Have a public no-argument constructor
241
- Be thread-safe for concurrent logger creation
242
- Handle context lifecycle properly
243
244
## Performance Considerations
245
246
### Adapter Selection Overhead
247
- **One-time Cost**: Adapter selection occurs once during LogManager construction
248
- **Fast Path**: No selection overhead during normal logging operations
249
- **Caching**: Created loggers are cached by the adapter registry
250
251
### Logger Creation Performance
252
- **Lazy Creation**: Loggers created on-demand when first requested
253
- **Context Reuse**: LoggerContext instances are reused across loggers
254
- **Message Factory Reuse**: Static MessageFactory instances minimize object creation
255
256
### Memory Management
257
- **Weak References**: Logger registry uses weak references to prevent memory leaks
258
- **Context Cleanup**: Proper cleanup when LoggerContext is shut down
259
- **Resource Sharing**: Shared resources between logger instances
260
261
## Error Handling
262
263
### Adapter Loading Failures
264
265
```java
266
try {
267
adapter = LoaderUtil.newCheckedInstanceOf(className, AbstractLoggerAdapter.class);
268
LOGGER.info("Using custom LoggerAdapter [{}].", className);
269
} catch (Exception e) {
270
LOGGER.error("Specified LoggerAdapter [{}] is incompatible.", className, e);
271
// Falls back to default adapter
272
adapter = new ApiLoggerAdapter();
273
}
274
```
275
276
### Logger Creation Failures
277
278
- **Graceful Degradation**: Falls back to simpler logger implementation
279
- **Error Logging**: Reports issues through StatusLogger
280
- **NoOp Fallback**: Returns NoOpLogger for recursive creation attempts
281
282
### Context Issues
283
284
- **Context Unavailable**: Creates logger with default context
285
- **Configuration Errors**: Uses default configuration if context configuration fails
286
- **Resource Cleanup**: Proper cleanup prevents resource leaks
287
288
## Thread Safety
289
290
All adapter components are fully thread-safe:
291
292
- **Adapter Selection**: One-time initialization during LogManager construction
293
- **Logger Creation**: Thread-safe logger creation and caching
294
- **Context Access**: Safe concurrent access to LoggerContext
295
- **Registry Operations**: Thread-safe operations in underlying registry
296
297
## Integration Points
298
299
### With LogManager
300
- **Automatic Integration**: LogManager automatically uses selected adapter
301
- **Configuration**: Respects adapter configuration from system properties
302
- **Lifecycle**: Adapter lifecycle tied to LogManager lifecycle
303
304
### With Log4j Components
305
- **API Integration**: Works with any log4j-api implementation
306
- **Core Integration**: Enhanced features when log4j-core is available
307
- **Context Integration**: Proper integration with LoggerContext lifecycle
308
309
### With JUL Framework
310
- **Standard Interface**: Provides standard JUL Logger interface
311
- **Handler Compatibility**: Works with existing JUL handlers when needed
312
- **Level Compatibility**: Integrates with JUL level system through translation