31.1 Logging Modern

Implement structured, context-aware logging to enable effective diagnostics and centralized log aggregation.

java.util.logging Configuration

import java.util.logging.*;

Logger logger = Logger.getLogger("com.example.App");
logger.setLevel(Level.INFO);

Handler handler = new ConsoleHandler();
handler.setFormatter(new SimpleFormatter());
logger.addHandler(handler);

logger.info("Application started");

Configure via logging.properties:

handlers=java.util.logging.ConsoleHandler
.level=INFO
com.example.level=FINE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

Structured Logging (JSON)

Use SLF4J + Logback or Log4j2 for structured output:

import org.slf4j.*;

Logger log = LoggerFactory.getLogger(MyClass.class);
log.info("User action", kv("userId", 123), kv("action", "login"));

Logback JSON encoder:

<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>

Output:

{"@timestamp":"2025-12-26T10:30:00Z","level":"INFO","message":"User action","userId":123,"action":"login"}

Context Propagation (MDC)

import org.slf4j.MDC;

MDC.put("requestId", UUID.randomUUID().toString());
logger.info("Processing request");
MDC.remove("requestId");

With virtual threads, use ScopedValue for context:

import java.lang.ScopedValue;

static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();

ScopedValue.where(REQUEST_ID, UUID.randomUUID().toString()).run(() -> {
  logger.info("Request: {}", REQUEST_ID.get());
});

Centralized Logging

  • Ship logs to aggregators (ELK, Loki, Splunk).
  • Use structured formats (JSON) for queryability.
  • Include correlation IDs across distributed services.

Async Logging

<!-- Logback async appender -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
  <appender-ref ref="FILE"/>
</appender>

Guidance

  • Use SLF4J as logging facade; bind to Logback or Log4j2.
  • Emit structured logs (JSON) for production systems.
  • Propagate request/trace IDs for correlation.
  • Avoid logging sensitive data (passwords, PII).
  • Use async appenders to minimize logging overhead.