Java: Practical Observability With Structured Logging

Introduction

When a production application fails, developers need to understand what happened, where it happened, and how many users were affected.

Traditional log messages often contain useful information, but unstructured text can be difficult to search and correlate. Structured logging makes important fields explicit so that logs can be queried consistently.

Why Structured Logging Helps

Compare these messages:

Payment failed for order 4821

and:

{
  "event": "payment_failed",
  "order_id": "4821",
  "provider": "example",
  "error_type": "timeout"
}

The structured representation separates the event name and its attributes. A logging platform can filter by event, group by provider, or count failures by error type.

Consistent field names are more important than choosing one particular naming convention.

Use a Logging Framework

SLF4J is commonly used as a logging facade in Java applications.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PaymentService {
    private static final Logger log =
        LoggerFactory.getLogger(PaymentService.class);

    public void processPayment(String orderId) {
        log.info(
            "Starting payment processing for orderId={}",
            orderId
        );
    }
}

This uses parameterized logging instead of constructing a message string eagerly.

To produce JSON logs, configure a compatible logging backend or encoder. SLF4J alone does not guarantee JSON output; the final format depends on the application’s logging configuration.

Include Context Without Leaking Secrets

Useful log fields may include a request ID, operation name, dependency name, error category, duration, outcome, or non-sensitive business identifier.

Avoid logging passwords, access tokens, session cookies, payment details, or entire request bodies by default.

Personal information should be minimized and handled according to the application’s privacy and security requirements. A log platform is still a data store and must be protected accordingly.

Correlate Logs Across Requests

A request ID helps connect related events. The application can generate or validate a correlation identifier at the request boundary and propagate it through downstream operations where appropriate.

Logging frameworks that support mapped diagnostic context can associate values with the current execution context. With asynchronous execution, context propagation must be configured correctly rather than assumed.

Distributed tracing adds further context when a request crosses several services. Trace IDs and span IDs help connect operations that cannot be understood from one application’s logs alone.

Choose Appropriate Log Levels

A useful policy distinguishes normal events from problems:

  • TRACE/DEBUG: Detailed diagnostic information.
  • INFO: Significant expected application events.
  • WARN: Unexpected situations that may recover or require attention.
  • ERROR: Failures that prevent an operation from completing.

Avoid logging every method entry at INFO level. Excessive logs increase storage costs and make important events harder to find.

Also avoid logging the same exception repeatedly at several layers unless each entry adds meaningful context.

Measure Latency and Failures

Logs are only one part of observability.

Metrics can answer questions such as how many payment requests failed, how long requests take at the 95th percentile, or how many background jobs are waiting.

Traces help explain the path of a specific request across services. Together, logs, metrics, and traces provide a more complete picture of system behavior.

Test Logging Behavior

Focus tests on important operational requirements:

  • Errors contain enough context for diagnosis.
  • Sensitive fields are not logged.
  • Correlation identifiers are propagated.
  • Structured fields use consistent names.
  • Unexpected exceptions retain appropriate stack traces.

Review log output using the same pipeline and configuration that production uses. Local console formatting may differ from deployed JSON output.

Conclusion

Structured logging makes production events easier to search, correlate, and analyze. Combine it with consistent log levels, data minimization, request correlation, metrics, and distributed tracing.

The goal is not to produce more logs. It is to produce the right information in a form that helps engineers make decisions quickly and safely.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *