Comprehensive logging framework module for Dropwizard applications providing configurable appenders, formatters, and logback integration
—
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.
Configure logging before YAML configuration is read, essential for early application startup logging.
/**
* Configure logging before YAML configuration is read
*/
public class BootstrapLogging {
/**
* Bootstrap logging with WARN level using default console appender
* Thread-safe and idempotent - safe to call multiple times
*/
public static void bootstrap();
/**
* Bootstrap logging with specified level using default console appender
* @param level the minimum logging level
*/
public static void bootstrap(Level level);
/**
* Bootstrap logging with specified level and custom layout
* @param level the minimum logging level
* @param layoutFactory factory for creating custom layout
*/
public static void bootstrap(Level level, DiscoverableLayoutFactory<ILoggingEvent> layoutFactory);
}Usage Examples:
// Basic bootstrap with WARN level
BootstrapLogging.bootstrap();
// Bootstrap with INFO level for more verbose startup logging
BootstrapLogging.bootstrap(Level.INFO);
// Bootstrap with custom layout
DropwizardLayoutFactory customLayout = new DropwizardLayoutFactory();
BootstrapLogging.bootstrap(Level.DEBUG, customLayout);
// Safe to call multiple times - subsequent calls are ignored
BootstrapLogging.bootstrap();
BootstrapLogging.bootstrap(Level.ERROR); // This call has no effectThread Safety:
ReentrantLock for thread-safe initializationLogging utility methods for system integration and logger context management.
/**
* Logging utility methods
*/
public class LoggingUtil {
/**
* Safely acquire LoggerContext with retry logic
* Handles cases where LoggerContext is not immediately available
* @return the Logback LoggerContext
* @throws IllegalStateException if context cannot be acquired
*/
public static LoggerContext getLoggerContext();
/**
* Redirect JUL (Java Util Logging) to SLF4J
* Thread-safe and idempotent - safe to call multiple times
* Installs SLF4JBridgeHandler to capture JUL events
*/
public static void hijackJDKLogging();
}Usage Examples:
// Get logger context for configuration
LoggerContext context = LoggingUtil.getLoggerContext();
// Configure appenders programmatically
Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME);
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
appender.setContext(context);
appender.start();
rootLogger.addAppender(appender);
// Redirect JDK logging to SLF4J (commonly done at application startup)
LoggingUtil.hijackJDKLogging();
// Now JUL loggers will route through SLF4J/Logback
java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger("com.example.MyClass");
julLogger.info("This will appear in Logback appenders");Abstract base class for resilient output streams that automatically recover from connection failures.
/**
* Base class for resilient output streams with recovery logic
*/
public abstract class ResilientOutputStreamBase extends OutputStream {
/**
* Get description of this stream for logging purposes
* @return human-readable description
*/
protected abstract String getDescription();
/**
* Open a new output stream (called on initial connection and reconnection)
* @return new OutputStream instance
* @throws IOException if stream cannot be opened
*/
protected abstract OutputStream openNewOutputStream() throws IOException;
/**
* Write a single byte with automatic recovery
* @param b the byte to write
* @throws IOException if write fails after retry attempts
*/
@Override
public void write(int b) throws IOException;
/**
* Write byte array with automatic recovery
* @param b the byte array
* @param off the offset
* @param len the length
* @throws IOException if write fails after retry attempts
*/
@Override
public void write(byte[] b, int off, int len) throws IOException;
/**
* Flush the output stream
* @throws IOException if flush fails
*/
@Override
public void flush() throws IOException;
/**
* Close the output stream
* @throws IOException if close fails
*/
@Override
public void close() throws IOException;
}Resilient TCP connection implementation that automatically reconnects on connection failures.
/**
* Resilient TCP connection as OutputStream with automatic reconnection
*/
public class ResilientSocketOutputStream extends ResilientOutputStreamBase {
/**
* Create resilient socket output stream
* @param host target hostname or IP address
* @param port target port number
* @param connectionTimeoutMs connection timeout in milliseconds
* @param sendBufferSize TCP send buffer size in bytes
* @param socketFactory factory for creating socket connections
*/
public ResilientSocketOutputStream(String host, int port, int connectionTimeoutMs,
int sendBufferSize, SocketFactory socketFactory);
/**
* Get description of this socket connection
* @return description in format "host:port"
*/
@Override
protected String getDescription();
/**
* Open new socket connection with configured parameters
* @return OutputStream from the socket connection
* @throws IOException if connection cannot be established
*/
@Override
protected OutputStream openNewOutputStream() throws IOException;
}Usage Example:
// Create resilient socket connection for log forwarding
String host = "log-server.example.com";
int port = 514;
int connectionTimeout = 5000; // 5 seconds
int sendBufferSize = 8192; // 8KB buffer
SocketFactory socketFactory = SocketFactory.getDefault();
ResilientSocketOutputStream socketStream = new ResilientSocketOutputStream(
host, port, connectionTimeout, sendBufferSize, socketFactory);
// Use with any appender that accepts OutputStream
OutputStreamAppender<ILoggingEvent> appender = new OutputStreamAppender<>();
appender.setOutputStream(socketStream);
appender.setEncoder(new PatternLayoutEncoder());
appender.start();
// Stream will automatically reconnect on network failures
try {
socketStream.write("Log message\n".getBytes());
socketStream.flush();
} catch (IOException e) {
// Connection failed and could not be reestablished
logger.error("Failed to write to remote log server", e);
}Ready-to-use socket appenders built on the resilient stream infrastructure.
TCP socket appender with resilient connection handling.
/**
* TCP socket appender with resilient connection handling
*/
public class DropwizardSocketAppender<E> extends OutputStreamAppender<E> {
/**
* Create TCP socket appender
* @param host target hostname
* @param port target port
* @param connectionTimeoutMs connection timeout
* @param sendBufferSize send buffer size
* @param socketFactory socket factory for connections
*/
public DropwizardSocketAppender(String host, int port, int connectionTimeoutMs,
int sendBufferSize, SocketFactory socketFactory);
}UDP socket appender for datagram-based log forwarding.
/**
* UDP socket appender with datagram support
*/
public class DropwizardUdpSocketAppender<E> extends OutputStreamAppender<E> {
/**
* Create UDP socket appender
* @param host target hostname
* @param port target port
*/
public DropwizardUdpSocketAppender(String host, int port);
}Usage Examples:
// TCP socket appender
DropwizardSocketAppender<ILoggingEvent> tcpAppender = new DropwizardSocketAppender<>(
"log-server.example.com", 514, 5000, 8192, SocketFactory.getDefault());
tcpAppender.setContext(context);
tcpAppender.setEncoder(encoder);
tcpAppender.start();
// UDP socket appender
DropwizardUdpSocketAppender<ILoggingEvent> udpAppender = new DropwizardUdpSocketAppender<>(
"syslog-server.example.com", 514);
udpAppender.setContext(context);
udpAppender.setEncoder(encoder);
udpAppender.start();public class ApplicationMain {
public static void main(String[] args) {
// 1. Bootstrap logging early
BootstrapLogging.bootstrap(Level.INFO);
// 2. Redirect JDK logging
LoggingUtil.hijackJDKLogging();
// 3. Log early startup messages
Logger logger = LoggerFactory.getLogger(ApplicationMain.class);
logger.info("Application starting...");
try {
// 4. Load and configure full logging system
DefaultLoggingFactory loggingFactory = loadLoggingConfiguration();
MetricRegistry metrics = new MetricRegistry();
loggingFactory.configure(metrics, "MyApplication");
logger.info("Logging system configured");
// 5. Start application
startApplication();
} catch (Exception e) {
logger.error("Application startup failed", e);
System.exit(1);
}
}
private static DefaultLoggingFactory loadLoggingConfiguration() {
// Load from YAML, environment, etc.
DefaultLoggingFactory factory = new DefaultLoggingFactory();
factory.setLevel("INFO");
// Add file appender with resilient network backup
FileAppenderFactory<ILoggingEvent> fileAppender = new FileAppenderFactory<>();
fileAppender.setCurrentLogFilename("./logs/application.log");
TcpSocketAppenderFactory<ILoggingEvent> networkAppender = new TcpSocketAppenderFactory<>();
networkAppender.setHost("log-aggregator.example.com");
networkAppender.setPort(514);
factory.setAppenders(Arrays.asList(fileAppender, networkAppender));
return factory;
}
}/**
* Custom resilient stream for database logging
*/
public class ResilientDatabaseOutputStream extends ResilientOutputStreamBase {
private final String jdbcUrl;
private final String username;
private final String password;
public ResilientDatabaseOutputStream(String jdbcUrl, String username, String password) {
this.jdbcUrl = jdbcUrl;
this.username = username;
this.password = password;
}
@Override
protected String getDescription() {
return "Database: " + jdbcUrl;
}
@Override
protected OutputStream openNewOutputStream() throws IOException {
try {
Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
return new DatabaseOutputStream(connection);
} catch (SQLException e) {
throw new IOException("Failed to connect to database", e);
}
}
}
// Usage with custom appender
ResilientDatabaseOutputStream dbStream = new ResilientDatabaseOutputStream(
"jdbc:postgresql://db.example.com/logs", "loguser", "logpass");
OutputStreamAppender<ILoggingEvent> dbAppender = new OutputStreamAppender<>();
dbAppender.setOutputStream(dbStream);
dbAppender.setEncoder(new JsonEncoder());
dbAppender.start();Install with Tessl CLI
npx tessl i tessl/maven-io-dropwizard--dropwizard-logging