0
# Utility Classes
1
2
Essential utility classes for logging system management including bootstrap configuration, JDK logging integration, and resilient network streams. These classes provide the foundational infrastructure for Dropwizard's logging system.
3
4
## Capabilities
5
6
### BootstrapLogging
7
8
Configure logging before YAML configuration is read, essential for early application startup logging.
9
10
```java { .api }
11
/**
12
* Configure logging before YAML configuration is read
13
*/
14
public class BootstrapLogging {
15
/**
16
* Bootstrap logging with WARN level using default console appender
17
* Thread-safe and idempotent - safe to call multiple times
18
*/
19
public static void bootstrap();
20
21
/**
22
* Bootstrap logging with specified level using default console appender
23
* @param level the minimum logging level
24
*/
25
public static void bootstrap(Level level);
26
27
/**
28
* Bootstrap logging with specified level and custom layout
29
* @param level the minimum logging level
30
* @param layoutFactory factory for creating custom layout
31
*/
32
public static void bootstrap(Level level, DiscoverableLayoutFactory<ILoggingEvent> layoutFactory);
33
}
34
```
35
36
**Usage Examples:**
37
38
```java
39
// Basic bootstrap with WARN level
40
BootstrapLogging.bootstrap();
41
42
// Bootstrap with INFO level for more verbose startup logging
43
BootstrapLogging.bootstrap(Level.INFO);
44
45
// Bootstrap with custom layout
46
DropwizardLayoutFactory customLayout = new DropwizardLayoutFactory();
47
BootstrapLogging.bootstrap(Level.DEBUG, customLayout);
48
49
// Safe to call multiple times - subsequent calls are ignored
50
BootstrapLogging.bootstrap();
51
BootstrapLogging.bootstrap(Level.ERROR); // This call has no effect
52
```
53
54
**Thread Safety:**
55
- Uses `ReentrantLock` for thread-safe initialization
56
- Idempotent - safe to call from multiple threads
57
- First call wins - subsequent calls are ignored
58
59
### LoggingUtil
60
61
Logging utility methods for system integration and logger context management.
62
63
```java { .api }
64
/**
65
* Logging utility methods
66
*/
67
public class LoggingUtil {
68
/**
69
* Safely acquire LoggerContext with retry logic
70
* Handles cases where LoggerContext is not immediately available
71
* @return the Logback LoggerContext
72
* @throws IllegalStateException if context cannot be acquired
73
*/
74
public static LoggerContext getLoggerContext();
75
76
/**
77
* Redirect JUL (Java Util Logging) to SLF4J
78
* Thread-safe and idempotent - safe to call multiple times
79
* Installs SLF4JBridgeHandler to capture JUL events
80
*/
81
public static void hijackJDKLogging();
82
}
83
```
84
85
**Usage Examples:**
86
87
```java
88
// Get logger context for configuration
89
LoggerContext context = LoggingUtil.getLoggerContext();
90
91
// Configure appenders programmatically
92
Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME);
93
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
94
appender.setContext(context);
95
appender.start();
96
rootLogger.addAppender(appender);
97
98
// Redirect JDK logging to SLF4J (commonly done at application startup)
99
LoggingUtil.hijackJDKLogging();
100
101
// Now JUL loggers will route through SLF4J/Logback
102
java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger("com.example.MyClass");
103
julLogger.info("This will appear in Logback appenders");
104
```
105
106
### ResilientOutputStreamBase
107
108
Abstract base class for resilient output streams that automatically recover from connection failures.
109
110
```java { .api }
111
/**
112
* Base class for resilient output streams with recovery logic
113
*/
114
public abstract class ResilientOutputStreamBase extends OutputStream {
115
/**
116
* Get description of this stream for logging purposes
117
* @return human-readable description
118
*/
119
protected abstract String getDescription();
120
121
/**
122
* Open a new output stream (called on initial connection and reconnection)
123
* @return new OutputStream instance
124
* @throws IOException if stream cannot be opened
125
*/
126
protected abstract OutputStream openNewOutputStream() throws IOException;
127
128
/**
129
* Write a single byte with automatic recovery
130
* @param b the byte to write
131
* @throws IOException if write fails after retry attempts
132
*/
133
@Override
134
public void write(int b) throws IOException;
135
136
/**
137
* Write byte array with automatic recovery
138
* @param b the byte array
139
* @param off the offset
140
* @param len the length
141
* @throws IOException if write fails after retry attempts
142
*/
143
@Override
144
public void write(byte[] b, int off, int len) throws IOException;
145
146
/**
147
* Flush the output stream
148
* @throws IOException if flush fails
149
*/
150
@Override
151
public void flush() throws IOException;
152
153
/**
154
* Close the output stream
155
* @throws IOException if close fails
156
*/
157
@Override
158
public void close() throws IOException;
159
}
160
```
161
162
### ResilientSocketOutputStream
163
164
Resilient TCP connection implementation that automatically reconnects on connection failures.
165
166
```java { .api }
167
/**
168
* Resilient TCP connection as OutputStream with automatic reconnection
169
*/
170
public class ResilientSocketOutputStream extends ResilientOutputStreamBase {
171
/**
172
* Create resilient socket output stream
173
* @param host target hostname or IP address
174
* @param port target port number
175
* @param connectionTimeoutMs connection timeout in milliseconds
176
* @param sendBufferSize TCP send buffer size in bytes
177
* @param socketFactory factory for creating socket connections
178
*/
179
public ResilientSocketOutputStream(String host, int port, int connectionTimeoutMs,
180
int sendBufferSize, SocketFactory socketFactory);
181
182
/**
183
* Get description of this socket connection
184
* @return description in format "host:port"
185
*/
186
@Override
187
protected String getDescription();
188
189
/**
190
* Open new socket connection with configured parameters
191
* @return OutputStream from the socket connection
192
* @throws IOException if connection cannot be established
193
*/
194
@Override
195
protected OutputStream openNewOutputStream() throws IOException;
196
}
197
```
198
199
**Usage Example:**
200
201
```java
202
// Create resilient socket connection for log forwarding
203
String host = "log-server.example.com";
204
int port = 514;
205
int connectionTimeout = 5000; // 5 seconds
206
int sendBufferSize = 8192; // 8KB buffer
207
SocketFactory socketFactory = SocketFactory.getDefault();
208
209
ResilientSocketOutputStream socketStream = new ResilientSocketOutputStream(
210
host, port, connectionTimeout, sendBufferSize, socketFactory);
211
212
// Use with any appender that accepts OutputStream
213
OutputStreamAppender<ILoggingEvent> appender = new OutputStreamAppender<>();
214
appender.setOutputStream(socketStream);
215
appender.setEncoder(new PatternLayoutEncoder());
216
appender.start();
217
218
// Stream will automatically reconnect on network failures
219
try {
220
socketStream.write("Log message\n".getBytes());
221
socketStream.flush();
222
} catch (IOException e) {
223
// Connection failed and could not be reestablished
224
logger.error("Failed to write to remote log server", e);
225
}
226
```
227
228
### Socket Appender Implementations
229
230
Ready-to-use socket appenders built on the resilient stream infrastructure.
231
232
#### DropwizardSocketAppender
233
234
TCP socket appender with resilient connection handling.
235
236
```java { .api }
237
/**
238
* TCP socket appender with resilient connection handling
239
*/
240
public class DropwizardSocketAppender<E> extends OutputStreamAppender<E> {
241
/**
242
* Create TCP socket appender
243
* @param host target hostname
244
* @param port target port
245
* @param connectionTimeoutMs connection timeout
246
* @param sendBufferSize send buffer size
247
* @param socketFactory socket factory for connections
248
*/
249
public DropwizardSocketAppender(String host, int port, int connectionTimeoutMs,
250
int sendBufferSize, SocketFactory socketFactory);
251
}
252
```
253
254
#### DropwizardUdpSocketAppender
255
256
UDP socket appender for datagram-based log forwarding.
257
258
```java { .api }
259
/**
260
* UDP socket appender with datagram support
261
*/
262
public class DropwizardUdpSocketAppender<E> extends OutputStreamAppender<E> {
263
/**
264
* Create UDP socket appender
265
* @param host target hostname
266
* @param port target port
267
*/
268
public DropwizardUdpSocketAppender(String host, int port);
269
}
270
```
271
272
**Usage Examples:**
273
274
```java
275
// TCP socket appender
276
DropwizardSocketAppender<ILoggingEvent> tcpAppender = new DropwizardSocketAppender<>(
277
"log-server.example.com", 514, 5000, 8192, SocketFactory.getDefault());
278
tcpAppender.setContext(context);
279
tcpAppender.setEncoder(encoder);
280
tcpAppender.start();
281
282
// UDP socket appender
283
DropwizardUdpSocketAppender<ILoggingEvent> udpAppender = new DropwizardUdpSocketAppender<>(
284
"syslog-server.example.com", 514);
285
udpAppender.setContext(context);
286
udpAppender.setEncoder(encoder);
287
udpAppender.start();
288
```
289
290
## Integration Examples
291
292
### Complete Bootstrap and Configuration
293
294
```java
295
public class ApplicationMain {
296
public static void main(String[] args) {
297
// 1. Bootstrap logging early
298
BootstrapLogging.bootstrap(Level.INFO);
299
300
// 2. Redirect JDK logging
301
LoggingUtil.hijackJDKLogging();
302
303
// 3. Log early startup messages
304
Logger logger = LoggerFactory.getLogger(ApplicationMain.class);
305
logger.info("Application starting...");
306
307
try {
308
// 4. Load and configure full logging system
309
DefaultLoggingFactory loggingFactory = loadLoggingConfiguration();
310
MetricRegistry metrics = new MetricRegistry();
311
loggingFactory.configure(metrics, "MyApplication");
312
313
logger.info("Logging system configured");
314
315
// 5. Start application
316
startApplication();
317
318
} catch (Exception e) {
319
logger.error("Application startup failed", e);
320
System.exit(1);
321
}
322
}
323
324
private static DefaultLoggingFactory loadLoggingConfiguration() {
325
// Load from YAML, environment, etc.
326
DefaultLoggingFactory factory = new DefaultLoggingFactory();
327
factory.setLevel("INFO");
328
329
// Add file appender with resilient network backup
330
FileAppenderFactory<ILoggingEvent> fileAppender = new FileAppenderFactory<>();
331
fileAppender.setCurrentLogFilename("./logs/application.log");
332
333
TcpSocketAppenderFactory<ILoggingEvent> networkAppender = new TcpSocketAppenderFactory<>();
334
networkAppender.setHost("log-aggregator.example.com");
335
networkAppender.setPort(514);
336
337
factory.setAppenders(Arrays.asList(fileAppender, networkAppender));
338
return factory;
339
}
340
}
341
```
342
343
### Custom Resilient Stream
344
345
```java
346
/**
347
* Custom resilient stream for database logging
348
*/
349
public class ResilientDatabaseOutputStream extends ResilientOutputStreamBase {
350
private final String jdbcUrl;
351
private final String username;
352
private final String password;
353
354
public ResilientDatabaseOutputStream(String jdbcUrl, String username, String password) {
355
this.jdbcUrl = jdbcUrl;
356
this.username = username;
357
this.password = password;
358
}
359
360
@Override
361
protected String getDescription() {
362
return "Database: " + jdbcUrl;
363
}
364
365
@Override
366
protected OutputStream openNewOutputStream() throws IOException {
367
try {
368
Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
369
return new DatabaseOutputStream(connection);
370
} catch (SQLException e) {
371
throw new IOException("Failed to connect to database", e);
372
}
373
}
374
}
375
376
// Usage with custom appender
377
ResilientDatabaseOutputStream dbStream = new ResilientDatabaseOutputStream(
378
"jdbc:postgresql://db.example.com/logs", "loguser", "logpass");
379
380
OutputStreamAppender<ILoggingEvent> dbAppender = new OutputStreamAppender<>();
381
dbAppender.setOutputStream(dbStream);
382
dbAppender.setEncoder(new JsonEncoder());
383
dbAppender.start();
384
```