Wednesday, October 22, 2014

Log4j 2 RollingFileAppender example

In this example we shall talk about the RollingFileAppender, one of the most basic appenders of Log4j. Log4j a thread-safe and flexible logging library for Java, licensed under the Apache Software Foundation.
The log4j architecture has three basic components, the logger, the appender and the layout. The logger is used to log the messages, the appender publishes the messages to different outputs and layout is used to format the log messages. All these components are configured in the log4j.xml file, which is placed in the application classpath.
A basic appender that is frequently used in log4j is the RollingFileAppender. It is an OutputStreamAppender that writes log messages to files, following a configured triggering policy about when a rollover should occur, and also following a configured rollover strategy about how to rollover the file.
Below, we will configure the RollingFileAppender to log files to a file, making use of its basic configuration parameters and using Log4j 2


Create the log4j2.xml file

The log4j2.xml file is placed under the resources folder of the project. This is where all logging components are configured. The rootLogger is set here, binded to a logging level and to the appender. The rootlogger is the logger configured in the log4j2.xml file, unless there is a custom logger implementation to be used in the application.
The logging levels are (from smaller to greater) : ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF. When a logging level is set, only messages belonging to this level or greater levels are printed.
Here, we use the RollingFileAppender to log messages to a file. The basic RollingFileAppender parameters to configure are described below:
  • append : when this field is set to true, the appender will append new logs to the file, when false ti will clear previous logs and write from the beginning.
  • immediateFlush : When set to true, every log record is immediately flushed to disk, if false, batch flushing is performed, thus improving the logger performance.
  • bufferedIO : If set to true, a buffer is used to write data and when the buffer is full the data is flushed.
  • bufferSize : This is the buffer size that will lead to data flush when reached.
  • filter : Here, we can define one or more filters to check if the records should be logged or not.
  • fileName : The name of the file that the appender writes to. If the file does not exist, it is created.
  • filePattern : This is where the pattern of the file is configured.
  • layout : This is the layout used to format the log event.
  • name : Here the appender name is set.
  • policy : The TriggeringPolicy to perform a rollover. The TriggeringPolicy may be composite, that combines multiple triggering policies and returns true if any of the configured policies return true. It may be on startup, that causes a rollover if the log file is older than the current JVM’s start time or it may be size based and time based, that cause a rollover according to size and time setting accordingly. The time based triggering policy uses two extra parameters, interval and modulate, to set how often the rollover will occur and wether it will occur on the interval boundary.
  • strategy : The RolloverStrategy that determines the name and location of the archived file. The default strategy may use the date/time pattern and the filePattern attributes specified on the RollingFileAppender. So, the date/time is replaced by current time in rollover, and if the filePattern has integer counter, the counter is incremented in rollover.
  • ignoreExceptions : When set to true, internal exceptions will be logged and then ignored. When set to false, exceptions will be propagated to the caller, instead, or can also be propagated to a FailoverAppender.
Below, we have focused on configuring the parameters that are related to rollover, so we have set the strategy and policy of the appender, as also the layout of log events and the fileName of files. We are using a SizeBasedTriggeringPolicy, with size set to 1 KB, so we expect the file to rollover when it reaches this size. We are also using a DefaultRolloverStrategy, with max number of files equal to 4, so we expect that the files in our logs folder will reach the max number of 4, and then the oldest ones will be removed as new ones will be created.
The layout used for the log events is:
  • %d{dd/MMM/yyyy HH:mm:ss,SSS} : the date pattern
  • %c{1} : print the class name
  • %m : print the message
  • %n to leave an empty line
The filePattern is set to ${log-path}/myexample-%d{yyyy-MM-dd}-%i.log, where the ${log-path} is set as a property in the file and sets the initial path of the logs folder, and %i is the counter that will be automatically incremented in rollover.
log4j2.xml
01<?xml version="1.0" encoding="UTF-8"?>
02<Configuration status="DEBUG">
03<Properties>
04<Property name="log-path">C:/logs/</Property>
05</Properties>
06<Appenders>
07<RollingFile name="RollingFile" fileName="${log-path}/myexample.log"
08filePattern="${log-path}/myexample-%d{yyyy-MM-dd}-%i.log" >
09<PatternLayout>
10<pattern>%d{dd/MMM/yyyy HH:mm:ss,SSS}- %c{1}: %m%n</pattern>
11</PatternLayout>
12<Policies>
13<SizeBasedTriggeringPolicy size="1 KB" />
14</Policies>
15<DefaultRolloverStrategy max="4"/>
16</RollingFile>
17</Appenders>
18<Loggers>
19<Logger name="root" level="debug" additivity="false">
20<appender-ref ref="RollingFile" level="debug"/>
21</Logger>
22<Root level="debug" additivity="false">
23<AppenderRef ref="RollingFile"/>
24</Root>
25</Loggers>
26</Configuration>

Create an Example class

Example.java class gets the rootLogger to log messages to the console. The logger is stated as a static field, initialized by the getLogger(String name) API method of org.apache.logging.log4j.LogManager. Example.java class has a main method, where the user is asked to type a number. The logger logs messages of different levels, using info(Object message), warn(Object message), debug(Object message), error( Object message) and fatal(Object message) API methods.
Example.java:
01package com.javacodegeeks.snippets.enterprise.log4jexample;
02 
03import java.io.BufferedReader;
04import java.io.IOException;
05import java.io.InputStreamReader;
06 
07import org.apache.logging.log4j.LogManager;
08import org.apache.logging.log4j.Logger;
09 
10 
11public class Example {
12 
13    static Logger log = LogManager.getLogger(Example.class.getName());
14 
15    public static void main(String[] args) throws IOException {
16        System.out.println("===> Please enter a number:\n===>");
17        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
18        int number = Integer.valueOf(br.readLine());
19        log.info("Info : number is " + number);
20        log.warn("Warning : number is " + number);
21        log.debug("Debug : number is " + number);
22        log.error("Error : number is " + number);
23        log.fatal("Fatal : number is " + number);
24         
25        if(number > 100) {
26            log.info("Info : You chose a number > 100 ");
27            log.warn("Warning : You chose a number > 100 ");
28            log.debug("Debug : You chose a number > 100 ");
29            log.error("Error : You chose a number > 100 ");
30            log.fatal("Fatal : You chose a number > 100 ");
31             
32        } else {
33            log.info("Info : You chose a number < 100 ");
34            log.warn("Warning : You chose a number < 100 ");
35            log.debug("Debug : You chose a number < 100 ");
36            log.error("Error : You chose a number < 100 ");
37            log.fatal("Fatal : You chose a number < 100 ");         
38        }
39        String numberStr = String.valueOf(number);
40        for(int i=0; i<=10; i ++) {
41            if(numberStr.contains(String.valueOf(i))) {
42                log.info("Info : Your number has the digit " + i);
43                log.warn("Warning : Your number has the digit " + i);
44                log.debug("Debug : Your number has the digit " + i);
45                log.error("Error : Your number has the digit " + i);
46                log.fatal("Fatal : Your number has the digit " + i);
47            }
48        }
49    }
50}

Run the application

Run the application more than once. Since the logging level is set to DEBUG, we expect that all logs will be produced and writen in the file. Since the file size is set to just 1 KB, rollover will occur immediately. You can change the logging level, and the policy and strategy params in the configuration file to practice more.