How to Use Log4J 2 with Spring Boot
14 CommentsLast Updated on October 21, 2024 by jt
Similar to accompanying application development activities, such as unit testing and documentation, logging is an integral part of any enterprise application. And Spring Boot applications are no different. Through logging, you get to see what the Spring Boot application code is really doing during monitoring, troubleshooting, and debugging. Spring Boot makes using a logging framework effortless. Out of the box, Spring Boot is very easy to use with Logback. With Spring Boot’s default configuration, you can start writing out log messages using the Logback framework.
But what if you want to use Log4J 2? Naturally, Spring Boot has support for Log4J 2 and a number of other popular logging frameworks. If you are new to Log4J 2, I wrote an introductory post on Log4J 2 here.
Configuring Spring Boot to use Log4J 2 is easy to do. In this post, I will explain how to configure Spring Boot to use Log4J 2 over the Simple Logging Facade for Java (SL4J) logging façade.
What is the SL4J Façade?
Logging has been an important topic in the Java community for a long time. There is actually a fair amount of competition among the various logging frameworks. Determining which logging framework is the best has been a vigorously debated topic in the Java community. I’m not entering the “which logging framework is best” debate in this post. Each framework has its own merits and faults, and the landscape is always evolving.
When developing enterprise class applications using the Spring Framework, a common theme is to avoid tight coupling. For example, using Spring’s dependency injection, it’s common to build an application which can use different data sources. It’s fairly common to use H2 in memory database for development and MySQL for your production database. This is made easy via the DataSource interface, which is part of the standard Java API. H2 has an implementation of the DataSource interface. MySQL has an implementation of the DataSource interface. Through Spring configuration, we tell the IoC container which one we want to use at run time.
Logging in Java has been the wild west for a long time. Sun / Oracle did include a logging API as part of Java, but it never really caught on in the Java community. I’m honestly having a hard time remembering ever seeing it used.
While the Open Source community does offer a number of great logging solutions, as a developer, you don’t want to couple your code to a specific logging framework. This is where SLF4J steps in.
SL4J is a façade for commonly used logging frameworks, such as Java Util Logging, Log4J, Log4J 2, and Logback. As a developer, you write logging code against the SL4J API. At deployment time, you have the flexibility to plug-in your desired logging framework. This is made possible through an intermediate bridge/adapter layer, like this.
SL4J does not provide a complete logging solution. With SL4J, you cannot perform operations such as configuring appenders or setting logging levels. You perform such configurations through a configuration file of the logging framework in use. As the configuration file remains external to the application, no dependencies exist between your application code and the underlying logging framework.
Should you not provide a logging configuration to SL4J, it won’t complain. You’re logging simply becomes a no-op operation. Which is nice since it won’t unintentionally cause errors in your application. But also something to be aware of, if you’re not getting logging output.
Maven Dependencies
To use Log4J 2 in a Spring Boot application, we need to add the required dependencies to the Maven POM. The required steps are:
- Use the latest Spring Boot version. At the time of writing this post, the Spring Boot version is 1.3.3.RELEASE.
. . . <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> . . .
Note: Spring Boot 1.2.4.RELEASE contains a bug, issue #3550. When you define a log level through application.properties, the bug changes the parent logger level, and in worst case the root logger level. Although the bug was fixed in 1.2.6.RELEASE, I suggest using the 1.2.8.RELEASE if you want to stick with 1.2.x.
- Add the SL4J dependencies.
. . . <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.19</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.5</version> </dependency> . . .
- Add the Log4J 2 dependencies.
. . . <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-jcl</artifactId> <version>2.5</version> </dependency> . . .
In the configuration code above, the log4j-jcl
artifact is Apache Log4J Commons Logging Bridge. It is required if you intend to route Spring Boot application.properties logging configuration to a Log4J 2 file appender.
- Exclude the built-in Logback dependency. This is necessary as Spring Boot will pick and use Logback if present in the classpath.
. . . <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <exclusions> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </exclusion> </exclusions> </dependency> . . .
The complete Maven POM is this.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>guru.springframework</groupId> <artifactId>blogposts</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Blog Posts</name> <description>Misc Blog Posts</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.2.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <start-class>guru.springframework.blog.BlogPostsApplication</start-class> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.10.Final</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Logging Messages in a Spring Boot Application
We will write log messages in the controller class of the Spring Boot application. As I have mentioned earlier, we will write log messages against the SL4J API. The code of the controller class is this.
IndexController.java
package guru.springframework.blog.controllers; 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"); return "index"; } }
In the IndexController
class above, we used the LoggerFactory
and Logger
classes of SL4J to log debug, info, warn, and error messages.
Configuring Logging in application.properties
In a Spring Boot application, you can externalize configuration to work with the same application code in different environments. The application.properties file is one of the many ways to externalize configuration. Let’s use it to externalize logging configuration.
In the default structure of a Spring Boot web application, you can locate the application.properties file under the Resources directory. In the application.properties file, you can define log levels of Spring Boot, application loggers, Hibernate, Thymeleaf, and lots more. You can also define a log file to write log messages in addition to the console. An example of an application.properties file with logging configuration is this.
logging.level.org.springframework.web=INFO logging.level.guru.springframework.blogs.controllers=INFO logging.level.org.hibernate=ERROR logging.file=logs/spring-boot-logging.log log4j.logger.org.thymeleaf=DEBUG
When you run the main class, INFO and higher level log messages of Spring Boot startup are logged to the console and the logs/spring-boot-logging.log file.
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 specified together, Spring Boot will ignore both.
Once the application starts, access it with the URL, http://localhost:8080. Spring Boot outputs INFO and higher level log messages of IndexController to the console and file.
Using a Log4J 2 Configuration File
Log4J 2 configuration through application.properties file might be sufficient for simple applications. But, enterprise applications have far more complex logging requirements. Log4J 2 supports advanced logging configurations through configuration files, such as properties, XML, JSON, and YAML. I have explained how to configure Log4J 2 using XML here.
In a Spring Boot application, you can specify a Log4J 2 XML configuration file as log4j2.xml or log4j2-spring.xml in the project classpath. The Spring Boot team however recommends using the -spring variant for your logging configuration. That is log4j2-spring.xml rather than log4j2.xml. If you use the standard log4j2.xml configuration, Spring Boot might not be able to completely control log initialization.
The code of the log4j2-spring.xml file, is this.
<?xml version="1.0" encoding="UTF-8"?> <Configuration monitorInterval="60"> <Properties> <Property name="log-path">applogs</Property> </Properties> <Appenders> <Console name="Console-Appender" target="SYSTEM_OUT"> <PatternLayout> <pattern> [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n </pattern>> </PatternLayout> </Console> <File name="App-File-Appender" fileName="${log-path}/app_log.log" > <PatternLayout> <pattern> [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n </pattern> </PatternLayout> </File> <File name="SpringBoot-File-Appender" fileName="${log-path}/springboot_log.log" > <PatternLayout> <pattern> [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n </pattern> </PatternLayout> </File> </Appenders> <Loggers> <Logger name="org.springframework.web" level="info" additivity="false"> <AppenderRef ref="SpringBoot-File-Appender"/> <AppenderRef ref="Console-Appender"/> </Logger> <Logger name="guru.springframework.blog.controllers" level="info" additivity="false"> <AppenderRef ref="App-File-Appender"/> <AppenderRef ref="Console-Appender"/> </Logger> <Root> <AppenderRef ref="Console-Appender"/> </Root> </Loggers> </Configuration>
In the configuration code above:
- Line 6 – Line 28: We defined a console appender and two file appenders.
- Line 30 – Line 33: We configured Spring Boot logging to log
INFO
and higher level messages to thespringboot_log.log
file and the console. - Line 34 – Line 37: We configured the loggers of the
guru.springframework.blog.controllers
package and its sub packages to logINFO
and higher level messages to theapp_log.log
file and the console.
Note: Spring Boot expects the log4j2-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.
When you run and access the application now, Spring Boot loads the log42-spring.xml file and uses the configuration to log messages to the springboot_log.log file, app_log.log file, and console.
Summary
Earlier in this post, I mentioned about the Log4J 2 supported configurations. I have written the following posts for each of the configuration which also apply to Spring Boot applications.
- Log4J 2 Configuration: Using Properties File
- Log4J 2 Configuration: Using XML
- Log4J 2 Configuration: Using JSON
- Log4J 2 Configuration: Using YAML
Which configuration to use is largely a matter of personal preferences and your logging needs. If your needs are fairly simple, often using the properties file is all you’ll need. But if you need to access more advanced logging features, you’ll need to use XML, JSON, or YAML. XML is structured and IDE friendly. But JSON/YAML are more fun to write in.
When it comes to adding logging statements to your code, there are always questions, such as “What to log and what not to?”, “How much to log?”, and so on. There are no concrete answers. You should resist the tendency to log everything because logging means more code and that comes with overhead. Also the more you log, the more difficult it becomes to locate specific log messages when you later need them. Instead, write logs as demonstrated by specific, verifiable needs.
You can find the code of this post on Github
Martin
Hi,
In console when I use application.properies or log4j2-spring.xml I have this error:
“ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.”
It disappear only if I use log4j2.xml configuration file.
How can I resolve this issue?
Ximanta
It is a known bug. The configuration in log4j2-spring.xml will work as expected.
https://github.com/spring-projects/spring-boot/issues/4809
You should be able to disable the message with the following system property:
-Dorg.apache.logging.log4j.simplelog.StatusLogger.level=OFF
Martin
Thank You Ximanta.
I don’t even notice that it works, this error confused me.
Niels Ull Harremoes
In log4j v2, you can use multiple configuration files, e.g.
log4j.configurationFile=base.log4j2.xml,myapp.log4j2.xml
How do I configure do this with spring boot?
George
@Niels
I am also trying to use spring boot with multiple configuration files for log4j2 and could not made it to work. Seems like Springboot looks for specific log4j2.xml (or -spring variant) and if it cannot find it (like in your example and in my case too) will load the one bundled with spring boot : org.springframework.boot.logging.log4j2.log4j2.xml.
Niels Ull Harremoes
We ended up moving to logback.
mikhey
There is a more simple way to configure maven dependencies – http://stackoverflow.com/a/27457106
gaurav singh
http://stackoverflow.com/questions/28349309/how-can-i-change-the-default-location-of-log4j2-xml-in-java-spring-boot
Looks like logging.config property in application.properties cannot be used.
SARVESH
How to configure log4j2 based on spring.profiles.active in spring boot? I have log4j2-dev.xml, log4j2-prod.xml.
I tried with logging.config. But it is not working.
Harinath
I am trying to externalize something like this in SpringBootServletInitializer implementation main class. it does create log file but writes only the lines mentioned in this method and nothing else.
is this correct way of externalizing the log4j2.xml with spring boot? am I doing anything wrong?
public static void main(final String[] args) throws Exception {
final SpringApplication application = new SpringApplication(MlmApplication.class);
String configHome = System.getProperty(“CONFIG_HOME”);
LoggerContext context = (LoggerContext) LogManager.getContext(false);
File file = new File(configHome + “/log4j2.xml”);
context.setConfigLocation(file.toURI());
LOG.info(“log4j2.xml path is set to ” + file.getAbsolutePath());
final Properties properties = new Properties();
application.setBannerMode(Mode.CONSOLE);
application.setDefaultProperties(properties);
application.run();
}
Oleg
Hi! It’s a good idea to use policies of log4j2 such as SizeBasedTriggeringPolicy, TimeBasedTriggeringPolicy and also use strategies DefaultRolloverStrategy for example with RollingFile Loggers. The power of log4g2 is in such possibilities.
Anthony
Somewhat of a trivial question – where does log-path come from in the XML file?
Swathi
how to show logs on web page using log4j2 in spring boot, And merge two different logs of two different servers and show them on web page.