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

Code Factory
6 min readNov 6, 2020

--

Donate : Link

WordPress Blog : Link

Applications… : Link

  • Log4j 2 provides a significant improvement in performance compared to its predecessor. It contains asynchronous loggers and supports multiple APIs including SLF4J, commons logging, and java.util.loggging.
  • 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>
  • The above configuration defines a simple ConsoleAppender and declares two loggers — an application specific logger and the the root logger.

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>
  • In the above RollingFile configuration, I’ve specified a SizeBasedTriggeringPolicy which will roll files over when the size reaches 1KB. The <DefaultRollOverStrategy max="20" /> element specifies the maximum number of log files that will be kept.
  • 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>
  • The interval attribute specifies the frequency of rollover. So if you want to roll files over every week, you can specify interval="7".
  • 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>
  • For Gmail -
<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>
  • If Username and Password are corect but still you got error related to Authentication Failed or Username or Password wrong then you have to ON Less secure app access. Default it is OFF.

URL: https://myaccount.google.com/security

  • Note that, for SMTP appender to work, you need to include spring-boot-starter-mail dependency to your pom.xml file -
<!-- 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>
  • Now you can either make all Loggers asynchronous, or create a mix of sync and async loggers.

1. Making all Loggers Asynchronous

  • Making all loggers asynchronous is very easy. You just need to set the SystemProperty Log4jContextSelector to org.apache.logging.log4j.core.async.AsyncLoggerContextSelector.
  • 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
  • or, when using a packaged jar -
mvn clean packagejava -jar target/log4j2-demo-0.0.1-SNAPSHOT.jar -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
  • or, define using System.setProperty()
  • 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");
  • or, create property file and define there

2. Using a mix of Sync and Async Loggers

  • You can also use a mix of sync and async loggers with Log4j 2 using the <AsyncLogger> configuration element.
  • 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

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 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>

log4j2.xml

<?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>

Log4j2DemoApplication.java

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");
}
}

--

--