Using Logback with Spring Boot
26 CommentsIn this post we will explore using Spring Boot’s default logging framework, Logback.
Logback makes an excellent logging framework for enterprise applications. It’s fast, and has simple but powerful configuration options, and comes with a small memory footprint. I introduced logback in my introductory post, Logback Introduction: An Enterprise Logging Framework.
In a series of posts on Logback, I’ve also discussed how to configure Logback using XML and Groovy. The posts are available as Logback Configuration: using XML and Logback Configuration: using Groovy.
In this post, I’ll discuss how to use Logback with Spring Boot. While there are a number of logging options for Java, the Spring Boot chose to use Logback for the default logger. Like many things in Spring Boot, Logback, by default, gets configured with sensible defaults.
Log Levels
Available Log Levels
Logback, and most Java logging frameworks has 5 log levels:
trace
– Detailed, fine grained, messages from program executiondebug
– Messages intended to help debug program executioninfo
– informational messages, often some type of event to recordwarn
– A warning message about an unusual conditionerror
– Message that an unexpected error occured.
Log Level Selection
When a log level is selected, the selected log level and all higher log levels will produce output.
trace
enabled –trace
,debug
,info
,warn
anderror
produce log output.debug
enabled –debug
,info
,warn
anderror
produce log output.info
enabled –info
,warn
anderror
produce log output.warn
enabled –warn
anderror
produce log output.error
enabled – Onlyerror
produces log output.
Log Level Inheritance
The log level can be set at the root, package segment, and class level The log level will be inherited up this chain. If you set a log level for a package segment, the log level will apply to all classes under that segment.
For example, if we set the log level on the package guru.springframework.controllers
to debug
all classes in guru.springframework.controllers
and classes in any sub-packages will have their log level set to debug
.
Log Level Inheritance Examples
Logger | Assigned Level | Inherited Level |
root | info | info |
guru | none | info |
guru.springframework | none | info |
guru.springframework .controllers | none | info |
Logger | Assigned Level | Inherited Level |
root | warn | warn |
guru | none | warn |
guru.springframework | debug | debug |
guru.springframework .controllers | none | debug |
Logger | Assigned Level | Inherited Level |
root | error | error |
guru | none | error |
guru.springframework | info | info |
guru.springframework .controllers | none | info |
guru.springframework .controllers.IndexController | trace | trace |
SLF4J – Simple Logging Facade for Java
SLF4J uses the Facade Design Pattern to provide an abstraction to popular Java logging frameworks.
Spring Boot uses SLF4J to allow for the easy configuration of alternate logging frameworks. Spring Boot starter artifacts include the SLF4J binding to Logback, and the Logback implementation.
When developing your Spring Boot Application, for logging, you will wish to use the SLFJ4 components, and NOT the logback components directly.
Should you ever wish to use a different logging implementation, you will be able to change without updating your application code.
Spring Boot Logback Example
Initial Setup
To follow this tutorial, you can create a new Spring Boot project using the Spring Initializr.
Add the following dependencies:
- Spring MVC
- Lombok
You can also find this project in my Github repository here.
Dependencies
We can examine the Maven dependency tree to see the dependencies the Spring Boot starter is adding to the project.
Here we can see the Spring Boot starter for Spring MVC (web) brings in the Spring Boot starter for logging. Under this dependency we can the the dependencies for Logback. Logback itself implements the binder for SLF4J, and includes the SLF4J API.
Creating Logback Loggers
Add the following Spring MVC controller to your Spring Boot project.
package guru.springframework.springlogback.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class IndexController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping(value = "/" )
Map<String, String> index(){
logger.trace("This is a trace message");
logger.debug("This is a debug message");
logger.info("This is an info message");
logger.warn("This is a warn message");
logger.error("This is an error message");
return Map.of("message", "Hello, World!");
}
}
In this example, we get an SLF4J logger from the SLF4J logger factory with the class of the controller.
When the index()
method is called, 5 logging statements, one for each log level, are called.
You can start your Spring Boot application and go to the url http:\\localhost:8080
in your browser. You’ll see the Hello World
message in the browser. In the console, you will see the following output.
2024-10-17T14:16:35.487-04:00 INFO 76058 --- [spring-logback] [nio-8080-exec-2] g.s.s.controller.IndexController : This is an info message
2024-10-17T14:16:35.487-04:00 WARN 76058 --- [spring-logback] [nio-8080-exec-2] g.s.s.controller.IndexController : This is a warn message
2024-10-17T14:16:35.487-04:00 ERROR 76058 --- [spring-logback] [nio-8080-exec-2] g.s.s.controller.IndexController : This is an error message
Notice, you are only seeing info
, warn
, and error
log messages. The trace
and debug
messages are not there.
This is because the default configuration Spring Boot uses sets the root log level to info
.
Creating Logback Loggers with Project Lombok
Project Lombok has become very popular for its features saving us from writing excessive cerimonial code. I previously covered Project Lombok in this post. In this post I wish to cover creating loggers using Project Lombok.
Project Lombok will generate code for you at compile time through a Java feature known as Annotation Processing. To use Project Lombok, be sure to add the dependency and enable Annotation processing in your IDE compiler settings.
Here is an example controller using Project Lombok to create its logger.
@Slf4j
@RestController
public class LombokController {
@RequestMapping(value = "/lombok" )
Map<String, String> index(){
log.trace("This is a trace message");
log.debug("This is a debug message");
log.info("This is an info message");
log.warn("This is a warn message");
log.error("This is an error message");
return Map.of("message", "Hello, World!");
}
}
In the above example, we annotate the class with the Project Lombok annotation @Slf4j
.
At compile time, Project Lombok will add the following to your class:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LombokController.class);
While it is a small time saver, its is easy to use. And in my opinion, your code is cleaner.
In this case, we are using the SLF4J logger. Project Lombok supports the popular Java logging frameworks.
Setting Log Levels
Setting Log Levels from the Command Line
We can pass --debug
or --trace
as command line arguments to change the log level of the root logger.
For finer control, we can change just the log level of our class using the following command line argument:
-Dlogging.level.guru.springframework.springlogback.controller=TRACE
If we are using the Spring Boot Maven Plugin to run the application, we can pass the following command line argument to change the log level.
mvn spring-boot:run
-Dspring-boot.run.arguments=--logging.level.guru.springframework.springlogback.controller=trace
If we are using the Spring Boot Gradle plugin, we can pass the following command line argument to change the log level.
./gradlew bootRun -Pargs=--logging.level.guru.springframework.springlogback.controller=TRACE
Setting Log Levels from Environment Variables
We can also control log levels by setting environment variables. For example, we could set:
export LOGGING_LEVEL_ROOT=ERROR
export LOGGING_LEVEL_GURU_SPRINGFRAMEWORK=TRACE
Setting Log Levels from application.properties
To change log levels from application.properties, we can add the following:
logging.level.root=error
logging.level.guru.springfamework=TRACE
Setting Log Levels in Logback XML Configuration
In the Logback XML Configuration file, we can set the following:
<logger name="guru.springframework" level="DEBUG" />
We’ll look closer at XML configuration later in this post.
Setting Log Levels Using Spring Boot Profiles
While developing in your local machine, it is common to set the log level to DEBUG
. This will give you detailed log messages for your development use. While on production, it is typical to set the log level to WARN
or above. This is to avoid filling your logs with excessive debug information and logging overhead while running in production. While logging is very efficient, there is still a cost.
There are two ways to set log levels using Spring Boot Profiles. Using appplication.properties and using the Logback configuration file.
To use application.properties with the profile name appended to “application”. For example, a properties file for the active profile dev
would be application-dev.properties
or application-dev.yaml
.
Spring Boot has addressed these requirements by extending Spring profiles for Logback configuration with the <springProfile>
element. Using this element in your logback-spring.xml
file, you can optionally include or exclude sections of logging configuration based on the active Spring profile.
Note: Support for <springProfile>
in Logback configuration is available from Spring Boot 1.3.0.M2 milestone onwards.
Here is an XML example to configure Logback using active Spring profiles.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<springProfile name="dev,staging">
<logger name="guru.springframework.controllers" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>>
</springProfile>
<springProfile name="production">
<logger name="guru.springframework.controllers" level="WARN" additivity="false">
<appender-ref ref="FILE" />
</logger>
</springProfile>
</configuration>
Log Level Configuration Hierarchy
If the log level is defined in multiple locations, the following hierarchy applies:
- Log Levels set in application.properties will override XML properties
- Log Levels set in application-<profile>.properties will override application.properties
- Log Levels set in environment variables will override application.properties and application-<profile>.properties
- Log Levels set via command line arguments will override environment variables
See Externalized Configuration for Spring Boot for additional information
Logback Configuration with Spring Boot
If you need more granular control over the Logback configuration, you can specify a configuration file.
If Spring Boot finds one of these 4 files on the classpath, it will load it over the default configuration.
- logback-spring.xml
- logback.xml
- logback-spring.groovy
- logback.groovy
Spring recommends using logback-spring.xml
over logback.xml
.
You can also include the Spring Boot default configuration an simply extend it with your customizations.
Following is an example logback-spring.xml
file.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="guru.springframework" level="DEBUG"/>
</configuration>
In this example file, we are including the base Spring Boot Logback configuration, and setting the log level of the package guru.springframework
to debug
.
You can learn more about Logback XML configuration in this post, and Groovy configuration files.
Logback File Logging
By default, Spring Boot will only write log output to the console.
To enable log output to a file, you need to set the file name in the property logging.file.name
or the directory to write log files to in the property logging.file.path
.
NOTE: If you set both values, only logging.file.name
is used.
The Spring Boot default configuration will rotate the log files when they reach 10 MB, and keep up to 7 archive log files. See the Spring Boot documentation if you would like to modify this behavior.
In the configuration code above, for the dev
and staging
profiles, we configured the guru.springframework.controllers
logger to log DEBUG
and higher level messages to console. For the production
profile, we configured the same logger to log WARN
and higher level messages to a file.
JSON Logging with Logback
For environments which need to use consolidated logging, it is common to use JSON log output. This is typically needed with distributed microservices.
If you need to setup JSON logging with Logback, check out this post!
Logback Auto-Scan Issue with Spring Boot
In a logback-spring.xml
file, you can enable auto-scan of the configuration by setting the scan="true"
attribute. With auto-scan enabled, Logback scans for changes in the configuration file. For any changes, Logback automatically reconfigure itself with them. You can specify a scanning period by passing a time period to the scanPeriod
attribute, with a value specified in units of milliseconds, seconds, minutes or hours.
For example, this code tells Logback to scan logback-spring.xml
after every 10 seconds.
<configuration debug="true" scan="true" scanPeriod="10 seconds" >
...
</configuration>
One limitation of Spring Boot Logback is that with springProfile
and springProperty
, setting auto-scan results in error.
ANSI Color Mode
For console output, Logback will apply coloring to the console output. Refer to the Logback configuration guide if you would like to customize this.
ANSI Color Mode on Windows
To enable ANSI colors on Windows, you will need add the Jansi library version 1.17 or higher to your classpath and enable Jansi in the Logback configuration.
Add the following Maven dependency:
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>2.4.1</version>
</dependency>
Following is a Logback configuration example to enable Jansi.
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<encoder>
<pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) -%kvp -%msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
ANSI Color Mode on Linux and macOS
For Linux and macOS no additional configuration is required. These operating systems typically support ANSI colors natively. They do not need Jansi on the classpath, but doing so is harmless.
Following is an example of ANSI color console log output.
Use Log4J2 Instead of Logback with Spring Boot
For long time, the Java community considered Log4J the “best” logging framework. The team behind Log4J announced its end of life in 2015. Log4J is still used in a lot older, legacy applications.
Log4J4 is the successor of Log4J, and had its first GA release in 2014.
To use Log4J2 instead of Logback with Spring Boot, the steps are simple and straightforward. To use Log4J2, we need to:
- Exclude Logback from our dependencies
- Add the Log4J2 dependency
- Add the Log4J2 configuration
Since our application code is using SLF4J, rather than the logging framework directly, no further changes are required.
Log4J2 Dependencies
First we need to exclude the Log4J2 dependency from our Spring Boot starter was follows:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
Next we need to add the Log4J2 Maven Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Log4J Configuration
The Spring Boot auto configuration will look for the Log4J2 configration in two files on the classpath:
log4j2-spring.xml
log4j2.xml
Following is an example log4j2-spring.xml
configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="com.foo.Bar" level="trace" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
Conclusion
The popularity of Logback is trending in the open source community. A number of popular open source projects use Logback for their logging needs. Apache Camel, Gradle, and SonarQube are just a few examples.
Logback is clearly has the capabilities to handle the needs of logging in a complex enterprise application. So, it’s no wonder the Spring Boot team selected Logback for the default logging implementation. As you’ve seen in this post, the Spring Boot team has provided a nice integration with Logback. Out of the box, Logback is ready to use with Spring Boot. In this post, you’ve seen how easy it is to configure Logback in Spring Boot as your logging requirements evolve.
The source code used in this tutorial is available in my Github account here.
Richard Langlois
Great article, I liked the way we can change the logging level, by using application.properties file.
Typo in:
“will be sufficeint”
Thanks,
Richard Langlois P. Eng.
Java Solutions Architect, Alithya, Montreal.
aghilkrishna
Hi,
can you please update that how to set the request id on each process logs ?
In log4j, setting the request id in MDC works fine but not in slf4j.
red
very helpful article, thank you
LG Optimusv
Is there any way to change the log file name programatically?
Lazar
Can you give an example with “scan=true” added. It would be just great. Because I am experiencing hard times with springProps and springProfile while live reload is unabled on configuration.
Ximanta
The Spring springProfile and springProperty elements have issue with scan . A section has been added for this.
This issue is open at:
https://github.com/spring-projects/spring-boot/issues/7955
partiza
Could you please explain why logger property is not static ? with static field logger doesn’t work..
private static final Logger logger = LoggerFactory.getLogger(MyClass.class.getClass())
Simanta Sarma
You can use
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
moses mansaray
Thanks for making this point clear “However, you cannot specify both the logging.file and logging.path properties together. If done, Spring Boot will ignore both.” Got caught out by the Official Spring LoggingApplicationListener jav.doc which said the opposite : “By default, log output is only written to the console. If a log file is required the
* {@code logging.path} and {@code logging.file} properties can be used.”.
Made change to use anyone of the 2 enable logging for me!
sunil
Really Great article …
sagar
Nice article to follow.
Sahil Verma
Superb article.
nicely explained. thumb zup for you 🙂
jbx
As someone else pointed out. The right way to declare the logger is:
`private static final Logger logger = LoggerFactory.getLogger(ClassName.class);`
This way the logger can also be used from `static` methods not just instance ones. Furthermore, having the logger `static` ensures that it only gets instantiated once per class (rather than for every instance). Also any sub classes that also declare their own `logger` will get their own instance without doing nasty field hiding, which is a code smell in itself.
Ifti
“The Spring Boot team however recommends using the -spring variant for your logging configuration, logback-spring.xml is preferred over logback.xml” – why? Any specific reason?
Steve Johnson
He explains that: “If you use the standard logback.xml configuration, Spring Boot may not be able to completely control log initialization.”
Serdar KUZUCU
Thank you for the great article !
sachin
does logback-spring.xml overrides application.properties or is it the other way round .
Guill
I prefer log4j2, just because it has the supplier parameter (lambda): logger.debug(“json: {}”, () -> json.toString())
Nidhi
Thanks. Well explained. Great article.
Ronak
I tried logging with application.properties, all the logging related properties and removed the log4j2.xml from resources, this works fine in local, but when i create the RPM of this and deploy on server , logs are not getting stored in file, while running service. if i run jar file over linux server everything works fine.
Here i need log level to be changed from application.properties, if anyone have idea, plz reply
Ivo
Here is the code of the base.xml file from the spring-boot github repo.
//404: Not Found
🙁
Tom
Property “logging.file” in application.properties File is not correct (anymore):
Use “logging.file.name” instead of “logging.file”
In higher versions of spring-boot-parent, property logging.file is deprecated.