Main Tutorials

Apache Log4j 2 Tutorials

log4j 2 logo

A simple log4j 2 hello world example.

Tested with

  • Log4j 2.11.2
  • Maven 3
  • Java 8
Note
Apache Log4j 2, the fastest Java logging framework, provides significant improvements over its predecessor, Log4j 1.x.

1. Project Directory

project directory

2. Maven


	<dependency>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-api</artifactId>
		<version>2.11.2</version>
	</dependency>
		
	<dependency>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-core</artifactId>
		<version>2.11.2</version>
	</dependency>
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>com.mkyong</groupId>
    <artifactId>log4j2</artifactId>
    <version>1.0</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <log4j.version>2.11.2</log4j.version>
        <disruptor.version>3.4.2</disruptor.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <!-- https://logging.apache.org/log4j/2.x/manual/async.html -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>${disruptor.version}</version>
        </dependency>

        <!-- slf4j bridge to log4j
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        -->

        <!-- SMTPAppender need this  -->
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.2</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.0</version>
                <executions>
                    <!-- Attach the shade into the package phase -->
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.mkyong.HelloWorld</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

</project>

3. log4j2.xml

3.1 Create a log4j2.xml in the project classpath.

src/resources/log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="com.mkyong" level="debug" additivity="false">
            <AppenderRef ref="LogToConsole"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>

For other format

4. Hello Log4j 2

4.1 Read this Log4j 2 API

HelloWorld.java

package com.mkyong;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HelloWorld {

    private static final Logger logger = LogManager.getLogger(HelloWorld.class);

    public static void main(String[] args) {

        logger.debug("Hello from Log4j 2");

        // in old days, we need to check the log level to increase performance
        /*if (logger.isDebugEnabled()) {
            logger.debug("{}", getNumber());
        }*/

        // with Java 8, we can do this, no need to check the log level
        logger.debug("{}", () -> getNumber());

    }

    static int getNumber() {
        return 5;
    }

}

Output


19:12:25.337 [main] DEBUG com.mkyong.HelloWorld - Hello from Log4j 2
19:12:25.340 [main] DEBUG com.mkyong.HelloWorld - 5

5. Log4j 2 Configuration

5.1 We can change the status to “trace”, “debug”, “info”, “warn”, “error” and “fatal” to enable the internal Log4j events, it will display many useful logs for the Log4j components. Read this for Log4j configuration

src/resources/log4j2.xml

<Configuration status="DEBUG">
    
</Configuration>

6. Log4j 2 Appenders

Some of the common Log4j appenders.

6.1 ConsoleAppender

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
		<!-- avoid duplicated logs with additivity=false -->
        <Logger name="com.mkyong" level="debug" additivity="false">
            <AppenderRef ref="LogToConsole"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>

6.2 FileAppender

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <File name="LogToFile" fileName="logs/app.log">
            <PatternLayout>
                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
        </File>
    </Appenders>
    <Loggers>
        <Logger name="com.mkyong" level="debug" additivity="false">
            <AppenderRef ref="LogToFile"/>
            <AppenderRef ref="LogToConsole"/>
        </Logger>
        <Logger name="org.springframework.boot" level="error" additivity="false">
            <AppenderRef ref="LogToConsole"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToFile"/>
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>

6.3 RollingFileAppender – Rotate log files daily or when the file size > 10MB.

log4j2.xml

<Configuration status="DEBUG">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <RollingFile name="LogToRollingFile" fileName="logs/app.log"
                    filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
			<PatternLayout>
				<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
			</PatternLayout>
			<Policies>
				<TimeBasedTriggeringPolicy />
				<SizeBasedTriggeringPolicy size="10 MB"/>
			</Policies>
		</RollingFile>
    </Appenders>
	
    <Loggers>
        <!-- avoid duplicated logs with additivity=false -->
        <Logger name="com.mkyong" level="debug" additivity="false">
            <AppenderRef ref="LogToRollingFile"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>

By default, it will create up to 7 archives on the same day.

sample
sample

We can override the default 7 archives with this DefaultRolloverStrategy


	<RollingFile name="LogToRollingFile" fileName="logs/app.log"
			filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
		<PatternLayout>
			<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
		</PatternLayout>
		<Policies>
			<TimeBasedTriggeringPolicy/>
			<SizeBasedTriggeringPolicy size="10 MB"/>
		</Policies>
		<DefaultRolloverStrategy max="10"/>
	</RollingFile>

6.4 RollingRandomAccessFileAppender – Similar to the RollingFileAppender, but faster.

log4j2.xml

	<RollingRandomAccessFile name="LogToRollingRandomAccessFile" fileName="logs/app.log"
			filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
		<PatternLayout>
			<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
		</PatternLayout>
		<Policies>
			<TimeBasedTriggeringPolicy/>
			<SizeBasedTriggeringPolicy size="1 MB"/>
		</Policies>
		<DefaultRolloverStrategy max="10"/>
	</RollingRandomAccessFile>

6.5 AsyncAppender – Make appender asynchronous. Increase performance.

log4j2.xml

<Configuration status="DEBUG">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>

        <RollingRandomAccessFile name="LogToRollingRandomAccessFile" fileName="logs/app.log"
               filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout>
                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="1 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="10"/>
        </RollingRandomAccessFile>

        <Async name="Async">
			<!-- reference to other appenders -->
            <AppenderRef ref="LogToRollingRandomAccessFile"/>
        </Async>

    </Appenders>
    <Loggers>
        <!-- avoid duplicated logs with additivity=false -->
        <Logger name="com.mkyong" level="debug" additivity="false">
            <AppenderRef ref="Async"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>

6.6 SMTPAppender – Need javax.mail to send email.

pom.xml

	<dependency>
		<groupId>com.sun.mail</groupId>
		<artifactId>javax.mail</artifactId>
		<version>1.6.2</version>
	</dependency>
log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <RollingRandomAccessFile name="LogToRollingRandomAccessFile" fileName="logs/app.log"
                filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout>
                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="1 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="10"/>
        </RollingRandomAccessFile>

        <SMTP name="LogToMail" subject="Error Log From Log4j"
              from="from@DOMAIN"
              to="to@DOMAIN"
              smtpHost="smtp.mailgun.org"
              smtpPort="25"
              smtpUsername="abc"
              smtpPassword="123"
              bufferSize="100">
        </SMTP>

    </Appenders>
    <Loggers>
        <Logger name="com.mkyong" level="debug" additivity="false">
            <AppenderRef ref="LogToRollingRandomAccessFile"/>
            <AppenderRef ref="LogToConsole"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToMail"/>
        </Root>
    </Loggers>
</Configuration>

Simulate an error


package com.mkyong;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HelloWorldError {

    private static final Logger logger = LogManager.getLogger(HelloWorldError.class);

    public static void main(String[] args) {

        try {
            System.out.println(getData());
        } catch (IllegalArgumentException e) {
            logger.error("{}", e);
        }

    }

    static int getData() throws IllegalArgumentException {
        throw new IllegalArgumentException("Sorry IllegalArgumentException!");
    }

}

Sample email

sample email
Note
Always refer to this official Log4j appenders

7. Asynchronous Loggers

7.1 To enable all loggers to asynchronous, we need 2 things :

  • The disruptor 3 is present in project class path.
  • Set system property log4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

7.2 If we try to configure log4j2.contextSelector and the disruptor is not present in the classpath, it will prompt the following error message :


$ mvn clean package

$ mvn -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector -jar target\log4j2-1.0.jar

java.lang.NoClassDefFoundError: com/lmax/disruptor/EventTranslatorVararg
    at java.lang.ClassLoader.defineClass1 (Native Method)
    at java.lang.ClassLoader.defineClass (ClassLoader.java:1009)
    at java.security.SecureClassLoader.defineClass (SecureClassLoader.java:174)
    at java.net.URLClassLoader.defineClass (URLClassLoader.java:545)
    at java.net.URLClassLoader.access$100 (URLClassLoader.java:83)
    at java.net.URLClassLoader$1.run (URLClassLoader.java:453)

7.3 To fix it, add disruptor

pom.xml

	<dependency>
		<groupId>com.lmax</groupId>
		<artifactId>disruptor</artifactId>
		<version>3.4.2</version>
	</dependency>

7.4 Run it again, with Log4j 2 configuration in debug status.

Asynchronous Loggers


$ java -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector -jar target\log4j2-1.0.jar

2019-03-25 21:11:23,919 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@464bee09
2019-03-25 21:11:23,921 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@464bee09,component=AsyncLoggerRingBuffer
2019-03-25 21:11:23,921 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@464bee09,component=StatusLogger
2019-03-25 21:11:23,922 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@464bee09,component=ContextSelector
2019-03-25 21:11:23,923 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@464bee09,component=Loggers,name=
2019-03-25 21:11:23,923 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@464bee09,component=Loggers,name=com.mkyong
2019-03-25 21:11:23,924 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@464bee09,component=Appenders,name=LogToConsole
2019-03-25 21:11:23,924 main DEBUG Registering MBean org.apache.logging.log4j2:type=AsyncContext@464bee09,component=Appenders,name=LogToRollingFile
//...
2019-03-25 21:11:24,020 pool-1-thread-1 DEBUG Stopped LoggerContext[name=AsyncContext@464bee09, org.apache.logging.log4j.core.async.AsyncLoggerContext@45fd9a4d] with 

Synchronous Loggers


2019-03-25 21:12:49,432 main DEBUG Registering MBean org.apache.logging.log4j2:type=57baeedf,component=StatusLogger
2019-03-25 21:12:49,433 main DEBUG Registering MBean org.apache.logging.log4j2:type=57baeedf,component=ContextSelector
2019-03-25 21:12:49,433 main DEBUG Registering MBean org.apache.logging.log4j2:type=57baeedf,component=Loggers,name=
2019-03-25 21:12:49,434 main DEBUG Registering MBean org.apache.logging.log4j2:type=57baeedf,component=Loggers,name=com.mkyong
2019-03-25 21:12:49,435 main DEBUG Registering MBean org.apache.logging.log4j2:type=57baeedf,component=Appenders,name=LogToConsole
2019-03-25 21:12:49,435 main DEBUG Registering MBean org.apache.logging.log4j2:type=57baeedf,component=Appenders,name=LogToRollingFile
//...
2019-03-25 21:12:49,449 pool-1-thread-1 DEBUG Stopped LoggerContext[name=57baeedf, org.apache.logging.log4j.core.LoggerContext@4ed5eb72] with status true

8. Mixing Synchronous and Asynchronous Loggers


<Configuration status="WARN">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>

        <RollingRandomAccessFile name="LogToRollingRandomAccessFile" fileName="logs/app.log"
                                 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout>
                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="1 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="10"/>
        </RollingRandomAccessFile>

    </Appenders>
    <Loggers>

        <!-- asynchronous loggers -->
        <AsyncLogger name="com.mkyong" level="debug" additivity="false">
            <AppenderRef ref="LogToRollingRandomAccessFile"/>
            <AppenderRef ref="LogToConsole"/>
        </AsyncLogger>

        <!-- synchronous loggers -->
        <Root level="error">
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>

Read this Asynchronous Loggers for Low-Latency Logging

Download Source Code

$ git clone https://github.com/mkyong/java-logging.git
$ cd log4j2
$ mvn clean package
$ java -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector -jar target\log4j2-1.0.jar

References

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
13 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
John
1 year ago

Log4j2 has been designed by insane morons.

They got the brilliant idea to interpret logged data, that is, most usually, data coming from external sources such as a potentially malicious user. This gave the infamous CVE-2021-44228.

They built it on a different API than log4j (v1) but they also got the brilliant idea to provide a bridge API which offers the API of log4j but with a log4j2 implementation. Except that, since they also got the brilliant idea that some settings should be very hard or impossible to change programmatically (such as the output file of a File appender), many functionalities of the old Log4j API are implemented as NO-OP in this bridge, without any warning or nothing. Result is, if you depend on a library that uses this shit, not only you can’t include the old log4j anymore (since it is in conflict with the bridge), but you won’t even know why nothing is working if by chance you used these doomed functionalities.

They got the brilliant idea to include, hidden in a fixed sub-folder of the META-INF folder of each artifact, a binary file listing the provided “log4j2 plugins”, whatever they are (Log4j2Plugins.dat). If your project uses, for instance, the maven-assembly-plugin in order to distribute a single, executable jar, then there might be different instances of this file in some cases (such as, including buth the above mentionned log4j-log4j2 bridge and the log4j2 core jar). But only one will be retained in the resulting jar, it will not work with insane errors like tens of “ERROR StatusLogger Unrecognized conversion specifier”… Of course the file is binary and in a custom format, so that you’ll need specific tools to know what is there and to merge the different instances if ever you diagnosed the problem and are fool enough to try to fix it. This was discovered years ago and to be fixed… in log4j3 ! The purpose of this being only to have a faster startup (they can also lookup plugins but they won’t if a Log4j2Plugins.dat is there), you would think that they could allow a setting to force the plugins discovery instead of using this garbage, but no, too hard for them.

Oh, last but not least, they got the brilliant idea to silently ignore any logging request if ever no configuration file (log2j2.property or log4j2.xml) is in the classpath. No warning, no error, no log, nothing, just figure that you didn’t put the file where it was expected.

Probably other design and implementation errors but so far only seen the previous ones.

John
1 year ago
Reply to  John

I just found this one : they add the brilliant idea that you must not even add an appender at runtime, so the API library doesn’t provide the methods to add appenders to existing loggers. And in case you do it anyway, using the core library, they had the brilliant idea to punish you, because the methods that adds an appender will also REMOVE all other previous appenders, configured in the configuration file. Just found out in their code because I didn’t understand why my 1st log message (before adding a specific appender) was where I expected and none of the next ones… Not insane, but psychopaths.

Gowtham
3 years ago

nice info

suresh
4 years ago

how to use org.apache.log4j.helpers.LogLog class in log4j2

priya
2 years ago
Reply to  suresh

hi suresh i have same isssue

Liubomyr
1 year ago

Great info, very clear to understand, thanks

Dawid Bielecki - dawciobiel
1 year ago

Very nice. Thanks.

Aditya Sriram M
4 years ago

Hi –

Any idea how to fix the log4j issue? Link: https://stackoverflow.com/questions/27361052/failing-to-load-log4j2-while-running-fatjar

I want to avoid using the ‘com.github.edwgiz’ library for mentioning the transformer.

John
1 year ago

Forget it and use it. That’s already a miracle that someone could implement a solution to fix yet another brilliant idea of the psychopaths who designed log2j2, include per-jar cached configuration data in an hermetic binary file at a fixed location…

If you use maven, do as advised, use the maven-share-plugin to produce the fat jar and configure it with the edwgiz transformer to produce and include a complete cache file.

Jack
4 years ago

Thx, very help me!!!

SomeGuy
3 years ago
Reply to  Jack

Downvoted for clarity

Aisha
4 years ago

Thanks it helps me so

Nitin
4 years ago

How to print only custom log level in .log file