Spring Boot Essentials

Logging in Spring Boot

18 min Lesson 8 of 13

Logging in Spring Boot

Every production Spring Boot application generates log output. Getting that output right — structured, at the correct verbosity, routed to the right destination — separates an app you can operate from one you can only guess at when things go wrong. This lesson covers the default logging stack Spring Boot gives you, how log levels work, and how to configure everything through application.properties or application.yml.

The Default Stack: SLF4J + Logback

Spring Boot uses SLF4J as its logging facade and Logback as the underlying implementation. Both arrive on the classpath automatically when you include spring-boot-starter (which is a transitive dependency of every other starter). You do not need to add any logging dependency manually for the vast majority of applications.

Why a facade? SLF4J separates the API you write against (org.slf4j.Logger) from the runtime that produces the output. You can swap Logback for Log4j 2 or java.util.logging later without touching a single line of application code. Spring Boot uses this same facade internally, so all framework logs flow through the same pipeline as yours.

Spring Boot also ships bridge JARs (jcl-over-slf4j, log4j-to-slf4j, jul-to-slf4j) that funnel legacy loggers into the SLF4J pipeline. This means third-party libraries that use Commons Logging, Log4j 1.x, or java.util.logging all end up in Logback automatically.

Getting a Logger

Declare a logger as a private static final field in each class. The conventional idiom with SLF4J is:

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @Service public class OrderService { private static final Logger log = LoggerFactory.getLogger(OrderService.class); public void placeOrder(Long orderId) { log.debug("Placing order id={}", orderId); // business logic ... log.info("Order {} placed successfully", orderId); } }

The {} placeholders are SLF4J's parameterised logging syntax. The string concatenation happens only if the log level is enabled, so there is no performance cost for a log.debug(...) call when debug logging is off.

Use Lombok's @Slf4j to eliminate the boilerplate. Adding @Slf4j from org.projectlombok:lombok generates the private static final Logger log = LoggerFactory.getLogger(...); field at compile time, keeping your class clean. The generated field is identical to what you would write by hand.

Log Levels

SLF4J defines five levels in ascending severity:

  • TRACE — finest-grained detail; typically individual method calls, loop iterations, or low-level protocol frames. Almost always disabled in production.
  • DEBUG — diagnostic information useful during development and troubleshooting. Usually disabled in production or enabled only for specific packages.
  • INFO — normal operational events: application started, request received, order placed. The default level for your own code.
  • WARN — something unexpected happened but the application recovered: a retry succeeded, a deprecated API was called, a configuration value was defaulted.
  • ERROR — a failure that requires attention: an unhandled exception, a failed external call, data corruption detected.

When you set a logger to a given level, that level and every level above it are enabled. Setting a package to DEBUG enables DEBUG, INFO, WARN, and ERROR for every class in that package.

Spring Boot Defaults

Out of the box, Spring Boot configures:

  • Root level: INFO — your application code and all third-party libraries log at INFO and above.
  • Spring internals: INFO for org.springframework packages.
  • Hibernate SQL: WARN — generated SQL is not logged unless you explicitly enable it.
  • Console appender: colourised output with timestamp, level, thread, logger name (class name), and message.

The default console format looks like this:

2024-03-15T10:42:01.123+00:00 INFO 12345 --- [main] com.example.OrderService : Order 42 placed successfully

Configuring Log Levels in application.properties

The primary way to change log levels is via application.properties (or application.yml) using the logging.level. prefix followed by the fully-qualified package or class name:

# Set the root logger to WARN (quieter in production) logging.level.root=WARN # Your application package: keep at INFO logging.level.com.example=INFO # Enable DEBUG for a single service class logging.level.com.example.OrderService=DEBUG # See all SQL generated by Hibernate (use during development only) logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.orm.jdbc.bind=TRACE # See Spring MVC request mapping details logging.level.org.springframework.web=DEBUG
Never leave org.hibernate.orm.jdbc.bind=TRACE enabled in production. It logs every bound parameter value, which will expose passwords, PII, and sensitive data in your log files. Use it only during local development to debug query issues, then remove it before committing.

Configuring the Log File

By default, Spring Boot logs only to the console. To also write to a file, set one of these properties:

# Write to a fixed file path logging.file.name=/var/log/myapp/app.log # Write to a file named spring.log inside this directory logging.file.path=/var/log/myapp

Spring Boot automatically applies a rolling policy when writing to a file: log files are rotated when they reach 10 MB, and up to 7 days of history is kept by default. You can tune both:

logging.logback.rollingpolicy.max-file-size=50MB logging.logback.rollingpolicy.max-history=30 logging.logback.rollingpolicy.total-size-cap=1GB

Customising the Output Pattern

The console and file patterns are also configurable without touching an XML file:

# Console output format logging.pattern.console=%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n # File output format (often more verbose) logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{50} - %msg%n

Structured Logging (JSON) — Spring Boot 3.4+

From Spring Boot 3.4, structured JSON logging is built in and requires only one property:

logging.structured.format.console=ecs

This produces Elastic Common Schema (ECS) JSON on the console — ideal for log-aggregation platforms such as OpenSearch, Elasticsearch, or Loki. Alternative formats are logstash and gelf. Each log event is a single JSON object, making it trivially parseable by any log collector.

Full logback-spring.xml — When You Need More Control

If application.properties is not enough — custom appenders, multiple files, different patterns per profile — create src/main/resources/logback-spring.xml. Spring Boot detects and uses it automatically. The -spring suffix (versus plain logback.xml) allows Spring to process <springProfile> elements:

<configuration> <springProfile name="prod"> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>/var/log/myapp/app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>/var/log/myapp/app.%d{yyyy-MM-dd}.gz</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="WARN"> <appender-ref ref="FILE"/> </root> </springProfile> <springProfile name="dev"> <root level="DEBUG"> <appender-ref ref="CONSOLE"/> </root> </springProfile> </configuration>

Log Groups

Spring Boot lets you define log groups — named aliases for a set of packages — and then control the whole group with one property. Two groups are predefined: web and sql.

# Use the built-in "web" group to debug all web-layer loggers at once logging.level.web=DEBUG # Use the built-in "sql" group to enable all SQL-related loggers logging.level.sql=DEBUG # Define a custom group logging.group.billing=com.example.billing,com.example.payment logging.level.billing=DEBUG

Summary

Spring Boot ships with SLF4J over Logback, preconfigured at INFO level with colour-coded console output and automatic file rolling. You control everything through logging.level.*, logging.file.*, and logging.pattern.* properties — no XML required for most applications. When you need profile-specific appenders or fine-grained routing, drop a logback-spring.xml file into src/main/resources. In the next lesson you will see how Spring Boot DevTools accelerates the development loop with automatic restarts and live reload.