Using Logback with Spring Boot
26 CommentsLogback makes an excellent logging framework for enterprise applications. It’s fast, have 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. Out of the box, Spring Boot makes Logback easy to use.
Creating Loggers
In a previous post, I wrote about creating a web application using Spring Boot. We’ll configure Logback for this application. The application contains a controller called IndexController,
to which we’ll add logging code. The code of IndexController
is this.
//package guru.springframework.controllers; import guru.springframework.helpers.SpringLoggingHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class IndexController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @RequestMapping("/") String index(){ 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"); new SpringLoggingHelper().helpMethod(); return "index"; } }
Let’s add a SpringLoggingHelper
class with logging code to the application. Although this class doesn’t do anything except emitting logging statements, it will help us understand configuring logging across different packages. Here is the code of SpringLoggingHelper
:
//package guru.springframework.helpers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SpringLoggingHelper { private final Logger logger = LoggerFactory.getLogger(this.getClass()); public void helpMethod(){ 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"); } }
In both the classes above, we wrote logging code against the SLF4J API. SLF4J is a façade for commonly used logging frameworks, such as Java Util Logging, Log4J 2, and Logback. By writing against SLF4J, our code remains decoupled from Logback, thus providing us the flexibility to plug-in a different logging framework, if required later.
If you are wondering about SLF4J and Logback dependencies, you don’t need to specify any. Spring Boot contains them too. Assuming you’re using Maven or Gradle to manage you Spring Boot project, the necessary dependencies are part of the dependencies under Spring Boot.
Run the SpringBootWebApplication
main class. When the application starts, access it from your browser with the URL, http://localhost:8080
The logging output on the IntelliJ console is this.
We haven’t written any configuration for Logback. The output of both the IndexController
and SpringLoggingHelper
classes are from the Logback root logger. Notice that the debug messages are not getting logged. Logback by default will log debug level messages. However, the Spring Boot team provides us a default configuration for Logback in the Spring Boot default Logback configuration file, base.xml
. In addition, Spring Boot provides provide two preconfigured appenders through the console-appender.xml
and file-appender.xml
files. The base.xml
file references both of them.
Here is the code of the base.xml
file from the spring-boot github repo.
//404: Not Found
Here you can see the Spring Boot has overridden the default logging level of Logback by setting the root logger to INFO
, which is the reason we did not see the debug messages in the example above. As we’ll see in the next section, changing log levels in Spring Boot is very simple.
Configuration via Spring Boot’s application.properties File
In a Spring Boot application, you can externalize configuration to work with the same application code in different environments. The application.properties
file is likely the most popular of several different ways to externalize Spring Boot configuration properties. In the default structure of a Spring Boot web application, you can locate the application.properties
file under the Resources
folder. In the application.properties
file, you can define log levels of Spring Boot, application loggers, Hibernate, Thymeleaf, and more. You can also define a log file to write log messages in addition to the console.
Here is an example of an application.properties
file with logging configurations.
logging.level.org.springframework.web=INFO logging.level.guru.springframework.controllers=DEBUG logging.level.org.hibernate=ERROR logging.file=logs/spring-boot-logging.log
Note: There is also a logging.path
property to specify a path for a logging file. If you use it, Spring Boot creates a spring.log
file in the specified path. However, you cannot specify both the logging.file
and logging.path
properties together. If done, Spring Boot will ignore both.
When you run the main class now and access the application, log messages from IndexController
and SpringLoggingHelper
are logged to the console and the logs/spring-boot-logging.log
file.
In the output, notice that debug and higher level messages of IndexController
got logged to the console and file. This is because in the application.properties
file, we specified DEBUG
as the log level for the guru.springframework.controllers
package that IndexController
is part of. Since we did not explicitly configure the SpringLoggingHelper
class, the default configuration of base.xml
file is used. Therefore, only INFO
and higher level messages of SpringLoggingHelper
got logged.
You can see how simple this is to use when you need to get more detailed log messages for a specific class or package.
Logback Configuration through an External File
Logback configuration through application.properties
file will be sufficient for many Spring Boot applications. However, large enterprise applications are likely to have far more complex logging requirements. As I mentioned earlier, Logback supports advanced logging configurations through XML and Groovy configuration files.
In a Spring Boot application, you can specify a Logback XML configuration file as logback.xml
or logback-spring.xml
in the project classpath. The Spring Boot team however recommends using the -spring variant for your logging configuration, logback-spring.xml
is preferred over logback.xml
. If you use the standard logback.xml
configuration, Spring Boot may not be able to completely control log initialization.
Here is the code of the 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.controllers" level="WARN" additivity="false"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </logger> <logger name="guru.springframework.helpers" level="WARN" additivity="false"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </logger> </configuration>
In the configuration code above, we included the base.xml
file in Line 3. Notice that we didn’t configure any appenders, rather we relied on the CONSOLE
and FILE
appenders which are provided by Spring Boot.
With the updated Spring Boot Logback configuration, our logging output now looks like this:
Note: Spring Boot expects the logback-spring.xml
configuration file to be on the classpath. However, you can store it in a different location and point to it using the logging.config
property in application.properties
.
Spring Boot Profiles in Logging
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.
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 SpringBoot 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>
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.
To pass a profile to the application, run the application with the -Dspring.profiles.active=
JVM argument.
For local development, in IntelliJ, select Run-> Edit Configurations, and set the JVM argument in the Run/Debug Configurations dialog box, like this.
Now, when we run the application with the dev
profile, we will see the following log output.
In the output above, observe the logging output of IndexController
. DEBUG
and higher log messages got logged to console based on the configuration of the dev
profile. You can restart the application with the production
profile to ensure that WARN
and higher log messages gets logged to the file.
Conditional Processing of Configuration File
Logback supports conditional processing of configuration files with the help of the Janino library. You can use <if>
, <then>
and <else>
elements in a configuration file to target several environments. To perform conditional processing, add the Janino dependency to your Maven POM, like this.
. . . <dependency> <groupId>org.codehaus.janino</groupId> <artifactId>janino</artifactId> <version>2.7.8</version> </dependency> . . .
The complete logback-spring.xml
file with conditional processing logic is this.
//>
In the code above, we specified a condition in the <if>
element to check whether the current active profile contains dev
. If the condition evaluates to true
, the configuration code within the <then>
element executes. In the <then>
element, we configured guru.springframework.helpers
to log DEBUG
and higher messages to console. We used the <else>
element to configure the logger to log WARN
and higher messages to the log file. The <else>
element executes for any profiles other than dev
.
When you run the application with the production
profile and access it, both loggers will log WARN
and higher messages to the log file, similar to this.
For the dev
profile, both loggers will log DEBUG
and higher messages to the console, similar to this.
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.
//Error on using auto-scan with springProfile -ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:39 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]] //Error on using auto-scan with springProperty -ERROR in ch.qos.logback.core.joran.spi.Interpreter@12:125 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]
The error occurs because of incompatibility issues. Spring Boot uses the JoranConfigurator
subclass to support springProfile
and springProperty
. Unfortunately, Logback’s ReconfigureOnChangeTask
doesn’t provide a hook to plug it in.
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.
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.