Log4J2 Setup

I feel that a decent guide on how exactly Log4J2 is setup is in order, because there isn’t a real clear explanation on Apache’s site. Now Apache, I know you guys make a lot of stuff, but seriously a lot of this stuff is just over-engineered.

Alright, on to the configuration stuff!

Here’s an example config file, with an explanation as to what is going on here(at least as far as I can understand it)

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
  <appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File" fileName="${sys:logFilename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </appenders>
  <loggers>
    <root level="ERROR">
      <appender-ref ref="Console" />
      <appender-ref ref="File"/>
    </root>
    <logger name="com.rm5248.Logtest2" level="ALL" />
  </loggers>
</configuration>

Okay, let’s start at the very top with the configuration tag:

<configuration status="OFF">

If you change the ‘status’ part of this to a level such as “ALL”, you’ll notice that Log4J2 sends out A LOT of information. As far as I can tell, this is just logging information that is part of Log4J2.

Alright, let’s go on to the appenders. When you create a logger, there are several appenders that you can use to send information to various places. The two appenders that we have here are for the console(i.e. System.out) and a file.

<appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File" fileName="${sys:logFilename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </appenders>

The PatternLayout that they have determines how the information will be printed out. For the File appender, there is a fileName property with sys:logFilename. This means that the logger will look for the system property of logFilename. This can be set by either:

  1. passing -DlogFilename=XXX to the program
  2. System.setProperty( “logFilename”, XXX )

If you use option #2, you must also reconfigure the logger as shown in this StackOverflow post.  Fortunately, the patters are in fact well documented.  There are a lot of other appenders out there to append to different things, but we’re not worried about that at the moment.

Okay, now on to the final section: the loggers themselves.

  <loggers>
    <root level="ERROR">
      <appender-ref ref="Console" />
      <appender-ref ref="File"/>
    </root>
    <logger name="com.rm5248.Logtest2" level="ALL" />
  </loggers>

As you can see here, we have a root logger and a specific logger.  The root logger has a level of ERROR, which means that everything descending from the root logger will print out all ERROR messages.  The root logger will also go two places: the Console logger and the File logger.

The second logger besides the root logger is logging just one specific file.  The log level for that file is ALL, which overrides the ERROR log level of the root logger.  Thus, all log messages from that file will be logged.  These messages will also be sent to both the CONSOLE log and FILE log, as those settings are inherited from the root logger.  Let’s say that we want to send those log messages to the FILE, but everything will also go to the CONSOLE. We would do something like this:

    <root level="ERROR">
      <appender-ref ref="Console" />
    </root>
    <logger name="com.rm5248.Logtest2" level="ALL" >
       <appender-ref ref="File" />
    </logger>

Since the more specific logger inherits from the root logger, all log messages from com.rm5248.Logtest2 go to the FILE and the CONSOLE.  There’s more stuff that you can do here with that, but I haven’t really delved into it too deeply.

Anyway, here’s the code that I was using when I was playing around with this.  Hopefully this will help you to get started.

XML Config File:

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
  <appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="File" fileName="${sys:logFilename}">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
  </appenders>
  <loggers>
    <root level="ERROR">
      <appender-ref ref="Console" />
      <appender-ref ref="File" />
    </root>
    <logger name="com.rm5248.Logtest2" level="ALL" />
  </loggers>
</configuration>

LogTest.java:

package com.rm5248;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URI;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.XMLConfigurationFactory;


public class LogTest {

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

	public static void main( String[] args ){
		File logConfigFile = new File( XML_CONFIG_FILE_GOES_HERE );
		System.setProperty( "logFilename", "filename.log" );		

		try {
			FileInputStream fis = new FileInputStream( logConfigFile );

			XMLConfigurationFactory fc = new XMLConfigurationFactory( );
			fc.getConfiguration(  new ConfigurationFactory.ConfigurationSource( fis ) );

			URI configuration = logConfigFile.toURI();
			Configurator.initialize("config", null, configuration);

			org.apache.logging.log4j.core.LoggerContext ctx =
					(org.apache.logging.log4j.core.LoggerContext) LogManager.getContext( true );
			ctx.reconfigure();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		logger.debug( "hi debug" );
		logger.info( "hi info" );
		logger.error( "hi error" );

		Logtest2.doSomething();
	}

}

Logtest2.java:

package com.rm5248;

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

public class Logtest2 {
	private static Logger logger = LogManager.getLogger( Logtest2.class );
	
	public static void doSomething(){
		logger.debug( "hello" );
		logger.error( "error?!" );
		logger.warn( "warning" );
		logger.info( "la la la" );
	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *