Spring Boot — How to use Log4j 2 with Spring Boot Example | Code Factory

  • In this article, you’ll learn how to integrate and configure Log4j 2 in Spring Boot applications. You’ll configure different types of appenders including RollingFileAppender and SMTPAppender. You’ll also learn how to use Async logging capabilities provided by Log4j 2.
  • The idea is to build a simple Spring Boot application from scratch and demonstrate how to go about integrating and configuring Log4j 2 in the app.

Adding Log4j2

  • All the Spring Boot starters depend on spring-boot-starter-logging, which uses Logback by default. For using Log4j2, you need to exclude spring-boot-starter-logging and add spring-boot-starter-log4j2 dependency.
  • Open pom.xml file and add the following snippet to the <dependencies> section
<!-- Exclude Spring Boot's Default Logging -->
<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>
<!-- Add Log4j2 Dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

Configuring Log4j2

  • Spring Boot automatically configures Log4j if it finds a file named log4j2.xml or log4j2.json or log4j2.yaml in the classpath.
  • In this article, we’ll configure log4j 2 using XML. Create a new file log4j2.xml inside src/main/resources directory, and add the following configuration to it -
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="LOG_PATTERN">
%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex
</Property>
</Properties>
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}" />
</Console>
</Appenders>
<Loggers>
<Logger name="com.codeFactory" level="debug" additivity="false">
<AppenderRef ref="ConsoleAppender" />
</Logger>
<Root level="info">
<AppenderRef ref="ConsoleAppender" />
</Root>
</Loggers>
</Configuration>

Adding a Rolling File Appender

  • If you want your logs to be written to a file, then you can use a RollingFile appender. RollingFile appender creates a new file whenever the log file reaches a certain threshold specified by the triggering policy.
  • It stores the old log files with names matching the pattern specified by the filePattern parameter
<RollingFile name="FileAppender" fileName="logs/log4j2-demo.log"
filePattern="logs/log4j2-demo-%d{yyyy-MM-dd}-%i.log">
<PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="1KB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
  • There is another common triggering policy called TimeBasedTriggeringPolicy which is used commonly in Log4j2. You can use TimeBasedTriggeringPolicy to specify how often a rollover should occur based on the most specific time unit in the date/time pattern specified in the filePattern attribute.
  • Here is how you can use the TimeBasedTriggeringPolicy in the above example to roll files over every day
<Policies>
<TimeBasedTriggeringPolicy interval="2" />
</Policies>
  • In the above example, the date/time pattern of the file is {yyy-MM-dd}, where the most specific time unit is dd (date). Therefore the TimeBasedTriggeringPolicy roll files over based on date. If the date/time pattern was yyy-MM-dd-HH, the rollover would occur based on hour.
  • Finally, To use the RollingFile appender, you need to add the above RollingFile configuration to the <Appenders> section inside log4j2.xml, and configure one of your loggers to use it like so
<Root level="info">
<AppenderRef ref="ConsoleAppender"/>
<AppenderRef ref="FileAppender"/>
</Root>

Adding an SMTP Appender

  • SMTP appender is very useful in production systems when you want to be notified about any errors in your application via email.
  • You can configure an SMTP appender to send ERROR emails to you using an SMTP server like so
<SMTP name="MailAppender" 
subject="Log4j2 Demo"
to="email@example.com"
from="log4j2-demo@example.com"
smtpHost="SMTPHost"
smtpPort="587"
smtpUsername="USERNAME"
smtpPassword="PASSWORD"
bufferSize="1">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout>
</SMTP>
<SMTP name="MailAppender" 
subject="Log4j2 Demo"
to="email@example.com"
from="log4j2-demo@example.com"
smtpHost="smtp.gmail.com"
smtpPort="587"
smtpProtocol="smtp"
smtpUsername="USERNAME"
smtpPassword="PASSWORD"
bufferSize="1">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout>
</SMTP>
<!-- Needed for SMTP appender -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

Asynchronous Logging

  • Log4j2 Supports Async loggers. These loggers provide a drastic improvement in performance compared to their synchronous counterparts.
  • Async Loggers internally use a library called Disruptor for asynchronous logging.
  • We need to include Disruptor dependency for using async loggers. Add the following to your pom.xml file
<!-- Needed for Async Logging with Log4j 2 -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
  • You can do that by adding the System Property at runtime like so -
mvn spring-boot:run -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
mvn clean packagejava -jar target/log4j2-demo-0.0.1-SNAPSHOT.jar -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
  • According to the Java specification, static initialization occurs in the order it is declared. Therefore, the System.setProperty call is guaranteed to happen before the Log4j initialization.
System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");
  • All the application specific logs will be asynchronous, and other root logs will be synchronous
<Loggers>
<AsyncLogger name="com.codeFactory" level="debug" additivity="false">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="FileAppender" />
</AsyncLogger>
<Root level="info">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="FileAppender" />
</Root>
</Loggers>

Creating the Project

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.codeFactory</groupId>
<artifactId>log4j2-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>log4j2-demo</name>
<description>Demo project for Spring Boot Log4j 2</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Exclude Spring Boot's Default Logging -->
<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>
<!-- Add Log4j2 Dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- Needed for SMTP appender -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- Needed for Async Logging with Log4j 2 -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="LOG_PATTERN">
%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex
</Property>
</Properties>
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}" />
</Console>
<RollingFile name="FileAppender" fileName="logs/log4j2-demo.log"
filePattern="logs/log4j2-demo-%d{yyyy-MM-dd}-%i.log">
<PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="1KB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
<SMTP name="MailAppender"
subject="Log4j2 Demo"
to="email@example.com"
from="log4j2-demo@example.com"
smtpHost="smtp.gmail.com"
smtpPort="587"
smtpProtocol="smtp"
smtpUsername="USERNAME"
smtpPassword="PASSWORD"
bufferSize="1">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout>
</SMTP>
</Appenders>
<Loggers>
<Logger name="com.codeFactory" level="debug" additivity="false">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="FileAppender" />
<AppenderRef ref="MailAppender" />
</Logger>
<Root level="info">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="FileAppender" />
<AppenderRef ref="MailAppender" />
</Root>
</Loggers>
</Configuration>
package com.codeFactory;import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author code.factory
*
*/
@SpringBootApplication
public class Log4j2DemoApplication implements ApplicationRunner {
private static final Logger LOGGER = LogManager.getLogger(Log4j2DemoApplication.class); static {
/* To activate STARTTLS for the mail session */
System.setProperty("mail.smtp.starttls.enable", "true");

/* NOTE: Nothing can appear before this initialization
* NOTE: This initializer must be in the class that contains your entry point */
System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");
}

public static void main(String[] args) {
SpringApplication.run(Log4j2DemoApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
LOGGER.debug("Debugging log");
LOGGER.info("Info log");
LOGGER.warn("Warning log");
LOGGER.error("Error log");
LOGGER.fatal("Fatal log");
}
}

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store