Spring Boot by default uses Logback framework for logging when we use Spring Boot Starter dependency. Apache Log4j 2 is the successor of Log4j which provides significant improvements over its predecessor Log4j 1.x and provides many of the features available in Logback. In this Spring Boot Log4j2 Example, we will learn how to configure the log4j 2 framework in Spring boot application.
Spring boot provides a default starter for logging spring-boot-starter-logging. It is included by default in spring-boot-starter. In order to use Log4j2, we will be excluding spring-boot-starter-logging
Folder Structure:
- Create a Maven project (maven-archetype-quickstart) “SpringBootLog4j2” and create a package for our source files “com.javainterviewpoint” under src/main/java
- Now add the following dependency in the POM.xml
<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>com.javainterviewpoint</groupId> <artifactId>SpringBootLog4j2</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>SpringBootLog4j2</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <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> --> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> <exclusion> <artifactId>logback-classic</artifactId> <groupId>ch.qos.logback</groupId> </exclusion> <exclusion> <artifactId>log4j-over-slf4j</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.4</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-yaml</artifactId> <version>2.7.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- Adding the dependency jackson-dataformat-yaml, jackson-databind to read the log4j2.yaml and log4j2.json configuration files
- Create the Java classes App.java under com.javainterviewpoint folder.
- Create log4j2.xml / log4j2.json / log4j2.yaml file under src/main/resources directory.
Spring Boot Log4j2 Example
Dependency Tree
[INFO] ------------------------------------------------------------------------ [INFO] Building SpringBootLog4j2 0.0.1-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ SpringBootLog4j2 --- [INFO] com.javainterviewpoint:SpringBootLog4j2:jar:0.0.1-SNAPSHOT [INFO] +- org.springframework.boot:spring-boot-starter:jar:1.5.1.RELEASE:compile [INFO] | +- org.springframework.boot:spring-boot:jar:1.5.1.RELEASE:compile [INFO] | | \- org.springframework:spring-context:jar:4.3.6.RELEASE:compile [INFO] | | +- org.springframework:spring-aop:jar:4.3.6.RELEASE:compile [INFO] | | +- org.springframework:spring-beans:jar:4.3.6.RELEASE:compile [INFO] | | \- org.springframework:spring-expression:jar:4.3.6.RELEASE:compile [INFO] | +- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.1.RELEASE:compile [INFO] | +- org.springframework:spring-core:jar:4.3.6.RELEASE:compile [INFO] | \- org.yaml:snakeyaml:jar:1.17:compile [INFO] +- org.springframework.boot:spring-boot-starter-log4j2:jar:1.5.1.RELEASE:compile [INFO] | +- org.apache.logging.log4j:log4j-slf4j-impl:jar:2.7:compile [INFO] | | \- org.slf4j:slf4j-api:jar:1.7.22:compile [INFO] | +- org.apache.logging.log4j:log4j-api:jar:2.7:compile [INFO] | +- org.apache.logging.log4j:log4j-core:jar:2.7:compile [INFO] | +- org.slf4j:jcl-over-slf4j:jar:1.7.22:compile [INFO] | \- org.slf4j:jul-to-slf4j:jar:1.7.22:compile [INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.7.4:compile [INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile [INFO] | \- com.fasterxml.jackson.core:jackson-core:jar:2.8.6:compile [INFO] \- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.7.4:compile
Spring boot Log4j2 Configuration
Spring Boot automatically configures Log4j2 the moment it finds a file named log4j2.xml or log4j2.json or log4j2.yaml in the classpath.
log4j2.xml
Create log4j2.xml file under src/main/resources folder
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Appenders> <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n" /> </Console> <File name="FileAppender" fileName="D:/JIP/Application.log"> <PatternLayout pattern="%d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n" /> </File> </Appenders> <Loggers> <!-- Logging custom package --> <Logger name="com.javainterviewpoint" level="debug" additivity="false"> <AppenderRef ref="ConsoleAppender"></AppenderRef> <AppenderRef ref="FileAppender"></AppenderRef> </Logger> <!-- Logging spring boot package --> <Logger name="org.springframework.boot" level="debug" additivity="false"> <AppenderRef ref="ConsoleAppender"></AppenderRef> <AppenderRef ref="FileAppender"></AppenderRef> </Logger> <Root level="warn"> <AppenderRef ref="ConsoleAppender"></AppenderRef> <AppenderRef ref="FileAppender"></AppenderRef> </Root> </Loggers> </Configuration>
log4j2.yaml
Spring Boot requires “jackson-dataformat-yaml” dependency to pick up the yaml file.
Configutation: name: Default Appenders: Console: name: ConsoleAppender target: SYSTEM_OUT PatternLayout: pattern: "%d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n" File: name: FileAppender fileName: D:/JIP/Application.log PatternLayout: pattern: "%d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n" Loggers: Root: level: debug AppenderRef: - ref: ConsoleAppender Logger: - name: com.javainterviewpoint level: debug AppenderRef: - ref: FileAppender level: debug
log4j2.json
Add “jackson-databind” dependency so that spring boot reads the json configuration
{ "configuration": { "name": "Default", "appenders": { "Console": { "name": "ConsoleAppender", "target": "SYSTEM_OUT", "PatternLayout": { "pattern": "%d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n" } }, "File": { "name": "FileAppender", "fileName": "D:/JIP/Application.log", "PatternLayout": { "pattern": "%d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n" } } }, "loggers": { "logger": { "name": "com.javainterviewpoint", "level": "debug", "appender-ref": [{"ref": "ConsoleAppender", "level":"debug"},{"ref": "FileAppender", "level":"debug"}] }, "logger": { "name": "org.springframework.boot", "level": "debug", "appender-ref": [{"ref": "ConsoleAppender", "level":"debug"},{"ref": "FileAppender", "level":"debug"}] }, "root": { "level": "debug", "appender-ref": {"ref": "ConsoleAppender"} } } } }
Log4j2 properties (log4j2.properties)
You can still add have the tradition Log4j2 properties file for configuring Log4j 2
name=PropertiesConfig appenders = console, file appender.console.type = Console appender.console.name = ConsoleAppender appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n appender.file.type = File appender.file.name = FileAppender appender.file.fileName=D:/JIP/Application_properties.log appender.file.layout.type=PatternLayout appender.file.layout.pattern= %d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n loggers=file logger.file.name=com.javainterviewpoint logger.file.level = debug logger.file.appenderRefs = file logger.file.appenderRef.file.ref = FileAppender rootLogger.level = debug rootLogger.appenderRefs = stdout rootLogger.appenderRef.stdout.ref = ConsoleAppender
App.java
package com.javainterviewpoint; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class App implements ApplicationRunner { private static Logger logger = LogManager.getLogger(App.class); public static void main(String[] args) { SpringApplication.run(App.class, args); } @Override public void run(ApplicationArguments applicationArguments) throws Exception { logger.debug("Debugging log"); logger.info("Info log"); logger.warn("Warning log"); logger.error("Error log"); logger.fatal("Fatal log"); } }
The App class main() method is the triggering point of our application, it in-turn calls Spring Boot’s SpringApplication class run() method which bootstrap our App application. We need to pass our App.class as an argument to our run() method. We have printed some logging statements.
Output:
Run the spring boot application using “mvn spring-boot:run”
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.5.1.RELEASE) 01:25 21:53:43.364 [main] [INFO] [com.javainterviewpoint.App] - Starting App on Jack-PC with PID 4228 (D:\sts-3.8.3.RELEASE\Workspace\SpringBootLog4j2\target\classes started by Jack in D:\sts-3.8.3.RELEASE\Workspace\SpringBootLog4j2) 01:25 21:53:43.365 [main] [DEBUG] [com.javainterviewpoint.App] - Running with Spring Boot v1.5.1.RELEASE, Spring v4.3.6.RELEASE 01:25 21:53:43.365 [main] [INFO] [com.javainterviewpoint.App] - No active profile set, falling back to default profiles: default 01:25 21:53:43.365 [main] [DEBUG] [org.springframework.boot.SpringApplication] - Loading source class com.javainterviewpoint.App 01:25 21:53:44.094 [main] [DEBUG] [org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar$SpringApplicationAdmin] - Application Admin MBean registered with name 'org.springframework.boot:type=Admin,name=SpringApplication' 01:25 21:53:44.158 [main] [DEBUG] [org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer] - ========================= AUTO-CONFIGURATION REPORT ========================= Positive matches: ----------------- GenericCacheConfiguration matched: - Cache org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration automatic cache type (CacheCondition) JmxAutoConfiguration matched: - @ConditionalOnClass found required class 'org.springframework.jmx.export.MBeanExporter'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition) - @ConditionalOnProperty (spring.jmx.enabled=true) matched (OnPropertyCondition) JmxAutoConfiguration#mbeanExporter matched: - @ConditionalOnMissingBean (types: org.springframework.jmx.export.MBeanExporter; SearchStrategy: current) did not find any beans (OnBeanCondition) JmxAutoConfiguration#mbeanServer matched: - @ConditionalOnMissingBean (types: javax.management.MBeanServer; SearchStrategy: all) did not find any beans (OnBeanCondition) JmxAutoConfiguration#objectNamingStrategy matched: - @ConditionalOnMissingBean (types: org.springframework.jmx.export.naming.ObjectNamingStrategy; SearchStrategy: current) did not find any beans (OnBeanCondition) Negative matches: ----------------- ActiveMQAutoConfiguration: Did not match: - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition) AopAutoConfiguration: Did not match: - @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition) ArtemisAutoConfiguration: Did not match: - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory' (OnClassCondition) BatchAutoConfiguration: Did not match: - @ConditionalOnClass did not find required classes 'org.springframework.batch.core.launch.JobLauncher', 'org.springframework.jdbc.core.JdbcOperations' (OnClassCondition) CacheAutoConfiguration: Did not match: - @ConditionalOnBean (types: org.springframework.cache.interceptor.CacheAspectSupport; SearchStrategy: all) did not find any beans (OnBeanCondition) Matched: - @ConditionalOnClass found required class 'org.springframework.cache.CacheManager'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition) Exclusions: ----------- None Unconditional classes: ---------------------- org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration 01:25 21:53:44.174 [main] [DEBUG] [com.javainterviewpoint.App] - Debugging log 01:25 21:53:44.175 [main] [INFO] [com.javainterviewpoint.App] - Info log 01:25 21:53:44.175 [main] [WARN] [com.javainterviewpoint.App] - Warning log 01:25 21:53:44.176 [main] [ERROR] [com.javainterviewpoint.App] - Error log 01:25 21:53:44.176 [main] [FATAL] [com.javainterviewpoint.App] - Fatal log 01:25 21:53:44.177 [main] [INFO] [com.javainterviewpoint.App] - Started App in 1.244 seconds (JVM running for 2.269)
Spring Boot Rolling File Appender
If you want a new log file to be created whenever the file reaches a certain threshold size, then you can go for RollingFile Appender, in order to add a RollingFile add the below code in the log4j2.xml
<RollingFile name="FileAppender" fileName="D:/JIP/Application_Roll.log" filePattern="D:/JIP/Application_Roll-%d{yyyy-MM-dd}-%i.log"> <PatternLayout> <Pattern>%d{MM:dd HH:mm:ss.SSS} [%t] [%level] [%logger{36}] - %msg%n</Pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="1 MB" /> </Policies> <DefaultRolloverStrategy max="5" /> </RollingFile>
As per the above configuration, a new file will be created whenever the log file size reaches 1 MB since we have set up the SizeBasedTriggeringPolicy to 1 MB, The <DefaultRollOverStrategy max=”5″ /> element defines the maximum number of log files which will be kept.
Happy Learning 🙂
Leave a Reply