Spring Boot Logging
BeginnerLogback is the default logging framework; configure log levels per package in application.properties and output structured JSON logs for log-aggregation pipelines.
Overview
Spring Boot uses Logback as the default logging framework, pre-configured with sensible defaults: INFO level for the application, WARN for most third-party libraries, and a console appender. Configuration is controlled through application.properties/YAML (for simple cases) or logback-spring.xml (for full control). In production environments — especially microservice deployments — structured JSON logging is essential: it lets log aggregators (ELK, Loki, Splunk) parse fields like traceId, spanId, serviceName, and level without fragile regex. Spring Boot 3 ships with Logback integration for the Logstash encoder and first-class support for MDC (Mapped Diagnostic Context) to attach per-request contextual fields.
Configuring log levels in application.properties
The simplest way to change log levels is via properties. Use logging.level.<package>=LEVEL. You can also set the pattern, file output, and file rolling policy. The logging.group feature lets you assign a single name to multiple packages for bulk level changes — Spring Boot ships with web and sql groups out of the box.
# application.properties
logging.level.root=WARN
logging.level.com.example=DEBUG
logging.level.org.springframework.web=INFO
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql=TRACE
# Built-in groups
logging.level.web=DEBUG # covers web-related Spring packages
logging.level.sql=DEBUG # covers Hibernate SQL packages
# File output
logging.file.name=/var/log/myapp/app.log
logging.logback.rollingpolicy.max-file-size=10MB
logging.logback.rollingpolicy.max-history=7Structured JSON logging with Logstash encoder
For centralized log aggregation, replace the default text pattern with structured JSON. Add logstash-logback-encoder as a dependency, then configure it in logback-spring.xml. MDC fields are automatically included in every JSON log line — populate MDC at the start of each request (or use Micrometer Tracing which does it automatically with traceId/spanId).
<!-- logback-spring.xml -->
<configuration>
<springProperty scope="context" name="appName" source="spring.application.name"/>
<appender name="JSON_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"service":"${appName}"}</customFields>
<includeMdcKeyName>traceId</includeMdcKeyName>
<includeMdcKeyName>spanId</includeMdcKeyName>
<includeMdcKeyName>userId</includeMdcKeyName>
</encoder>
</appender>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="JSON_CONSOLE"/>
</root>
</springProfile>
<springProfile name="!prod">
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
</configuration>MDC for per-request contextual fields
Mapped Diagnostic Context (MDC) is a thread-local map that Logback includes in every log line from that thread. Populate it in a servlet filter or Spring interceptor to attach fields like requestId, userId, and tenantId. With Micrometer Tracing (Spring Boot 3), traceId and spanId are automatically injected into MDC, enabling distributed trace correlation across microservices.
// MDC filter — adds requestId to every log line for the request lifetime
@Component
@Order(1)
public class MdcRequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws ServletException, IOException {
String requestId = Optional.ofNullable(req.getHeader("X-Request-ID"))
.orElse(UUID.randomUUID().toString());
MDC.put("requestId", requestId);
try {
chain.doFilter(req, res);
} finally {
MDC.clear(); // always clear to prevent thread-pool contamination
}
}
}
// Usage — MDC fields auto-appear in JSON log output
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
public Order placeOrder(OrderRequest req) {
log.info("Placing order productId={} qty={}", req.productId(), req.qty());
// JSON output: {"level":"INFO","message":"Placing order...","requestId":"abc123",...}
}Key Points to Remember
- 1Spring Boot auto-configures Logback with INFO/WARN defaults; change levels via logging.level.<package> without any XML
- 2logging.group lets you bulk-control levels: logging.level.web=DEBUG toggles all Spring MVC packages at once
- 3logback-spring.xml (not logback.xml) allows Spring-specific features like <springProfile> and <springProperty>
- 4Logstash encoder emits JSON with automatic MDC field inclusion — essential for ELK, Loki, and Splunk pipelines
- 5Always MDC.clear() in a finally block to prevent stale context leaking across thread-pool reuse
- 6Micrometer Tracing (Boot 3) auto-populates MDC with traceId/spanId, enabling distributed trace correlation
Interview Questions
Sign in to ask AriaHow do you change the log level for a specific package in Spring Boot without touching XML config?
What is MDC and why must you always call MDC.clear() at the end of a request?
What is the difference between logback.xml and logback-spring.xml, and why does Spring Boot recommend the latter?
How would you set up structured JSON logging for a microservice deployed in Kubernetes with log forwarding to Loki?
How does Micrometer Tracing integrate with Logback to provide distributed trace correlation?
Ask Aria about Spring Boot Logging
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.