Structured logging, request tracing, and log rotation
How LoggingInterceptor stamps each request with a trace ID, how Logback writes structured output to rotating files, and how to tune verbosity per package.
Use this file to discover all available pages before exploring further.
Every HTTP request that reaches the Products API is automatically tracked from arrival to completion by LoggingInterceptor. The interceptor generates a unique trace ID for each request, writes that ID into the SLF4J Mapped Diagnostic Context (MDC), and logs the method, URI, response status, and wall-clock duration. Logback then stamps that trace ID onto every log line emitted during the request’s lifetime, so you can search your log files for a single ID and see the full picture of what happened.
The three lifecycle hooks each serve a distinct purpose:
Hook
Fires
What it logs
preHandle
Before the controller method
HTTP method, request URI, client IP, and the newly generated trace ID
postHandle
After the controller method returns
HTTP response status and total request duration in milliseconds
afterCompletion
After the response is committed
Exception message and stack trace if an unhandled exception occurred
MDC.clear() in afterCompletion removes the trace ID from the thread’s context so it does not leak into the next request handled by the same thread pool worker.
A typical request produces two lines in logs/application.log:
2026-05-19 14:23:01 [http-nio-8080-exec-3] INFO c.z.s.i.LoggingInterceptor - a3f1b2c4-... - === REQUEST START === | Method: GET | URI: /api/v1/products | RemoteAddr: 127.0.0.12026-05-19 14:23:01 [http-nio-8080-exec-3] INFO c.z.s.i.LoggingInterceptor - a3f1b2c4-... - === REQUEST END === | Status: 200 | Duration: 12ms
The %X{traceId} token is replaced by the UUID written to the MDC in preHandle. If a log line is emitted outside of a request (e.g., during startup), that token renders as an empty string.The console pattern is more compact and omits the thread name and trace ID for readability during development:
Writes all levels to standard output. Includes the trace ID bracket so you can correlate local development output with a specific request.
FILE
Writes all levels to logs/application.log. Rotates by size and date. Archived files follow the pattern logs/application-2026-05-19.0.log.
ERROR_FILE
Writes only ERROR-level lines to logs/error.log. Useful for monitoring: tail this file or ship it to an alerting system without processing the full application log.
Triggers rotation when the active file reaches 10 MB
maxHistory
10
Keeps at most 10 rotated archive files
totalSizeCap
100MB
Deletes the oldest archives if the total exceeds 100 MB
Rotated files are written to the same logs/ directory with the naming pattern logs/application-{date}.{index}.log. On a busy service that writes 10 MB per rotation period you will retain up to 10 rotated files before the oldest are automatically pruned.
Override the logging level for any package directly in application.properties — no restart required when using Spring Boot DevTools during development:
# Reduce Spring web dispatcher noiselogging.level.org.springframework.web=WARN# Set application code to INFO for a quieter local sessionlogging.level.com.zegel.springboot=INFO
Each logging.level.<package> entry is independent, so you can tune verbosity across libraries and your own code without affecting other loggers.