When developing Spring Boot applications, you’ll inevitably need to configure logging. During development, you want detailed debug information, but in production you only want the necessary logs saved to a file. This article covers Spring Boot 3.x logging configuration step by step, from the basics to practical usage.
Spring Boot’s Default Logging Behavior
Spring Boot outputs logs from startup without any special configuration. This is because Spring Boot adopts SLF4J as the logging facade and Logback as the implementation by default.
If you’re using starters like spring-boot-starter-web, spring-boot-starter-logging is automatically included as a dependency. By default, logs at INFO level and above are printed to the console.
Changing Log Levels with application.properties
Let’s start with the simplest approach. Using application.properties, you can change log levels without creating any XML files.
# Application-wide log level
logging.level.root=INFO
# Log level for specific packages
logging.level.com.example.myapp=DEBUG
logging.level.org.springframework.web=WARN
logging.level.root sets the default level for the entire application, while logging.level.<package> lets you fine-tune specific packages. A common pattern during development is to enable DEBUG only for your own packages while suppressing the Spring framework’s own logs.
Basic Structure of logback-spring.xml
For more advanced configuration, create a Logback configuration file at src/main/resources/logback-spring.xml.
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
A Logback configuration file is built around three main elements:
- appender defines the output destination and format
- logger configures settings for specific packages
- root defines the global default settings
By naming the file logback-spring.xml instead of logback.xml, you gain access to Spring Boot-specific features. For example, environment-specific configuration via springProfile tags and referencing properties defined in application.properties do not work with logback.xml.
Customizing the Console Appender
The console output format can be freely customized using pattern. Here are some commonly used patterns:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{40}) - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
%d{...}— timestamp format%thread— thread name%-5level— log level (-means left-aligned, padded to 5 characters)%logger{40}— logger name (up to 40 characters)%msg— log message%n— newline%highlight,%cyan— colorization (useful for readability in development)
Colorized output is convenient in development, but ANSI escape sequences are unnecessary in production or log files. It’s a good idea to split the configuration by environment.
File Output and Log Rotation
In production, you’ll want logs saved to a file. Since unbounded log file growth is a real problem, always configure rotation from the start using RollingFileAppender.
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
maxFileSize— maximum size per file (rolls to a new file when it exceeds 10MB)maxHistory— number of days to retain (keeps 30 days of logs)totalSizeCap— total size limit across all log files (up to 1GB)
Adding .gz to the filename pattern causes older log files to be automatically compressed with gzip.
One important caveat: Logback does not automatically create the logs directory. Specifying a non-existent directory will cause an error at startup, so either run mkdir logs beforehand or specify an absolute path to a directory you know exists.
Switching Log Configuration by Environment
Using Spring Boot’s Profile feature, you can apply different log configurations for development and production. See also the Profile article for details on environment-specific configuration.
<configuration>
<springProfile name="dev">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{40}) - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</springProfile>
<springProfile name="prod">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</springProfile>
</configuration>
Setting spring.profiles.active=prod in application.properties activates the production configuration. You can easily achieve a workflow where detailed DEBUG logs are shown on the console in development, while only INFO and above are saved to a file in production.
Note that in containerized environments (Docker, Kubernetes, etc.), it’s also common practice to write logs to stdout and pipe them into an external log aggregation system instead of writing to files. Choose the approach that fits your environment.
A Complete Practical Configuration Example
Finally, here is a complete configuration example suitable for real-world use. It handles both development and production environments, including per-package log level tuning.
<configuration>
<property name="LOG_PATH" value="logs" />
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/application.log</file>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
<logger name="com.example.myapp" level="DEBUG" />
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE" />
</root>
<logger name="org.springframework" level="WARN" />
<logger name="com.example.myapp" level="INFO" />
</springProfile>
</configuration>
Using <property> tags to define variables reduces duplication and improves maintainability.
When you want to automatically include contextual information such as request IDs or user IDs in your logs, MDC (Mapped Diagnostic Context) is a useful mechanism. It will be covered in a separate article, but it’s worth knowing as a feature that stores values in thread-local storage and automatically attaches them to log output.
Troubleshooting Log Configuration
Here is a summary of common logging issues and how to resolve them:
- No logs are output → Check for syntax errors in
logback-spring.xml. Look forLogback configuration errorin the startup console output. - Cannot write to file → Verify that the log directory exists and that the process has write permissions.
- Log level changes are not taking effect → Review configuration precedence. Generally,
logback-spring.xmltakes priority overapplication.properties, which takes priority over the defaults.
Log Operations in Production
Here are a few key points to keep in mind when operating logs in production.
Use INFO or above in production, and DEBUG in development. DEBUG and TRACE produce too much log volume and can negatively impact disk usage and performance.
Rotation configuration should be considered mandatory. If log files grow without bound, they will fill up disk space and cause the application to stop.
Never log personal or sensitive information (passwords, tokens, credit card numbers, etc.). Be careful not to accidentally output such data during debugging.
Summary
This article walked through Spring Boot logging configuration step by step, from the basics to practical use.
Starting from simple log level changes in application.properties and progressing to full-blown configuration with logback-spring.xml, the article covers the knowledge needed for real-world use. With environment-specific configuration switching and log rotation included, you should now be able to implement logging that is ready for production.
Combined with logging configuration, you can also monitor your application using Spring Boot Actuator. Give it a try as you work toward production-ready operations.