analytics

Saturday, April 10, 2010

Log4j

Overview


Log4j is a Reliable, Fast and Flexible Logging Framework (APIs) written in Java which is distributed under the Apache Software License.

Log4j is highly configurable through external configuration files at runtime. It views the logging process in terms of levels of priorities and offers mechanisms to direct logging information to a great variety of destinations, such as a database, file, console, UNIX Syslog etc.

Pros N Cons of Logging:

Logging is an important component of the software development. A well written logging code offers quick debugging, easy maintenance, and structured storage of an application's runtime information.

Logging does have its drawbacks also. It can slow down an application. If too verbose, it can cause scrolling blindness. To alleviate these concerns, log4j is designed to be reliable, fast and extensible.

Since logging is rarely the main focus of an application, the log4j API strives to be simple to understand and to use.

log4j Features:


• log4j is thread-safe.
• log4j is optimized for speed.
• log4j is based on a named logger hierarchy.
• log4j supports multiple output appenders per logger.
• log4j supports internationalization.
• log4j is not restricted to a predefined set of facilities.
• Logging behavior can be set at runtime using a configuration file.
• log4j is designed to handle Java Exceptions from the start.
• log4j uses multiple levels, namely ALL, TRACE, DEBUG, INFO, WARN, ERROR and FATAL.
• The format of the log output can be easily changed by extending the Layout class.
• The target of the log output as well as the writing strategy can be altered by implementations of the Appender interface.
• log4j is fail-stop. However, altough it certainly strives to ensure delivery, log4j does not guarantee that each log statement will be delivered to its destination.

log4j Installation:


Download the latest Log4j distribution from Apache website (http://jakarta.apache.org/log4j/docs/download.html) and put the log4j-xxx.jar in your project class path. For Java web application, you can place the jar file in WEB-INF/lib folder. For Java applications, you can place the jar in any folder, but remember to add the folder to your CLASSPATH.

Next we need to configure the Log4j library to our requirements. Log4j reads its configurations from log4j.properties file (or log4j.xml) placed in the CLASSPATH

 
There are two types of objects available with Log4j framework.


Core Objects: These are mandatory objects of the framework and required to use the framework.
Support Objects: These are optional objects of the framework and support core objects to perform addition but important tasks.

Core Objects


Logger Object:

public class Logger, the top level layer is Logger which provides Logger object. Logger is responsible for handling the majority of log operations. A logger ties the appender with the log messages that are coming from the Java application. Basically, a logger tells that the log messages from these packages should go to some appender which will log the message in the defined layout.

Appender Object:

public interface Appender, Appender is responsible for controlling the output of log operations. The Appender object is responsible for publishing logging information to various preferred destinations such as a database, file, console, UNIX Syslog etc.

Layout Object:

public abstract class Layout, this layer provides objects which are used to format logging information in different styles. Layout layer provides support to appender objects to before publishing logging information.
Layout objects play an important role in publishing logging information in a way that is human-readable and reusable.

Following is a virtual diagram showing different components of Log4J Framework:

 
 
Support Objects


There are other important objects in the log4j framework that play a vital role in the logging framework:

Level Object:

The Level object defines the granularity and priority of any logging information. There are seven levels of logging defined within the API: OFF, DEBUG, INFO, ERROR, WARN, FATAL, and ALL.

Filter Object:

The Filter object is used to analyze logging information and make further decisions on whether that information should be logged or not.

An Appender objects can have several Filter objects associated with them. If logging information is passed to a particular Appender object, all the Filter objects associated with that Appender need to approve the logging information before it can be published to the attached destination.

ObjectRenderer:

The ObjectRenderer object is specialized in providing a String representation of different objects passed to the logging framework. This object is used by Layout objects to prepare the final logging information.

LogManager:

The LogManager object manages the logging framework. It is responsible for reading the initial configuration parameters from a system-wide configuration file or a configuration class.

 
log4j - Configuration


Here I will explain how you can configure those core components using a configuration file. Configuring log4j involves assigning the Level, defining Appender, and specifying Layout objects in a configuration file.

The log4j.properties file is a log4j configuration file which keeps properties in key-value pairs. By default, the LogManager looks for a file named log4j.properties in the CLASSPATH.

• The level of the root logger is defined as DEBUG and attaches appender named X to it.
• Set the appender named X to be a valid appender.
• Set the layout for the appender X

log4j.properties Syntax:


Following is the syntax of log4j.properties file for an appender X:

# Define the root logger with appender X
log4j.rootLogger = DEBUG, X
# Set the appender named X to be a File appender
log4j.appender.X=org.apache.log4j.FileAppender
# Define the layout for X appender
log4j.appender.X.layout=org.apache.log4j.PatternLayout
log4j.appender.X.layout.conversionPattern=%m%n

log4j.properties Example:


Using the above syntax, we define the following in log4j.properties file:

• The level of the root logger is defined as DEBUG and attaches appender named FILE to it.
• The appender FILE is defined as org.apache.log4j.FileAppender and writes to a file named "log.out" located in the log directory.
• The layout pattern defined is %m%n, which means the printed logging message will be followed by a newline character.

# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=${log}/log.out
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n

log4j - Logging Levels


The org.apache.log4j.Level class provides following levels but you can also define your custom levels by sub-classing the Level class.


How Level Works


A log request of level p in a logger with level q, is enabled if p >= q. This rule is at the heart of log4j. It assumes that levels are ordered. For the standard levels, we have ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF.

Following example makes it clear that how we can filter our all the DEBUG and INFO messages. This program makes use of logger method setLevel( Level.X) to set a desired logging level:

This example would print all the messages except Debug and Info:

import org.apache.log4j.*;

public class LogClass {
private static org.apache.log4j.Logger log = Logger.getLogger(LogClass.class);
public static void main(String[] args) {
log.setLevel(Level.WARN);
log.trace("Trace Message!");
log.debug("Debug Message!");
log.info("Info Message!");
log.warn("Warn Message!");
log.error("Error Message!");
log.fatal("Fatal Message!");
}
}

When you compile and run LogClass program it would generate following result:

Warn Message!
Error Message!
Fatal Message!


Setting Levels using Configuration File:


Log4j provides you configuration file based level setting which puts you free from changing source code when you want to change debugging level.

Following is an example configuration file which would do the same as we did using log.setLevel(Level.WARN) method in the above example.

# Define the root logger with appender file
log = /usr/home/log4j
log4j.rootLogger = WARN, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=${log}/log.out
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n


Appenders:

Apache log4j provides Appender objects which are primarily responsible for printing logging messages to different destinations such as consoles, files, sockets, NT event logs, etc.

Each Appender object has different properties associated with it, and these properties indicate the behavior of that object.

 
We can add an Appender object to a Logger by including the following setting in the configuration file with the following method:


log4j.logger.[logger-name]=level, appender1,appender..n

As the example configuration demonstrates, it is possible to add many Appender objects to a logger in a comma-separated list, each printing logging information to separate destinations.

All the possible appender options are:


• AppenderSkeleton
• AsyncAppender
• ConsoleAppender
• DailyRollingFileAppender
• ExternallyRolledFileAppender
• FileAppender
• JDBCAppender
• JMSAppender
• LF5Appender
• NTEventLogAppender
• NullAppender
• RollingFileAppender
• SMTPAppender
• SocketAppender
• SocketHubAppender
• SyslogAppender
• TelnetAppender
• WriterAppender


Layout:


We have used PatternLayout with our appender. All the possible options are:

• DateLayout
HTMLLayout
PatternLayout
• SimpleLayout
• XMLLayout

Using HTMLLayout and XMLLayout you can generate log in HTML and in XML format as well.


log4j - Sample Program


We have seen how to create a configuration file. This tutorial would teach you how to generate debug messages and log them in a simple text file.

Following is a simple configuration file created for our example. Let me re-iterate it once again:

• The level of the root logger is defined as DEBUG and attaches appender named FILE to it.
• The appender FILE is defined as org.apache.log4j.FileAppender and writes to a file named "log.out" located in the log directory.
• The layout pattern defined is %m%n, which means the printed logging message will be followed by a newline character.

So the content of log4j.properties file would be as follows:


# Define the root logger with appender file
log = /usr/home/log4j
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=${log}/log.out
log4j.appender.FILE.MaxFileSize=2MB
log4j.appender.FILE.MaxBackupIndex=2
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n

Using log4j in Java Program:


The following Java class is a very simple example that initializes, and then uses, the Log4J logging library for Java applications.

import org.apache.log4j.Logger;

import java.io.*;
import java.sql.SQLException;
import java.util.*;

public class log4jExample{

/* Get actual class name to be printed on */
static Logger log = Logger.getLogger(log4jExample.class.getName());
public static void main(String[] args) throws IOException,SQLException{
log.debug("Hello this is an debug message");
log.info("Hello this is an info message");
}
}

Compilation and Run:


Here are the steps to compile and run the above mentioned program. Make sure you have set PATH and CLASSPATH appropriately before proceeding for the compilation and execution.

All the libraries should be available in CLASSPATH and your log4j.properties file should be available in PATH. So do the following:

1. Create log4j.properties as shown above.
2. Create log4jExample.java as shown above and compile it.
3. Execute log4jExample binary to run the program.

You would get following result, inside /usr/home/log4j/log.out file:

Hello this is an debug message
Hello this is an info message

 
log4j - Logging Methods


Logger class provides a variety of methods to handle logging activities. The Logger class does not allow us to instantiate a new Logger instance but it provides two static methods for obtaining a Logger object:

• public static Logger getRootLogger();
• public static Logger getLogger(String name);

Here the first of the two methods returns the application instance's root logger and does not have a name. Any other named Logger object instance is obtained through the second method by passing the name of the logger. The name of the logger can be any string you can pass, usually class or package name e.g.

static Logger log = Logger.getLogger(log4jExample.class.getName());

Logging Methods:

Once we obtain an instance of a named logger, we can use several methods of the logger to log messages. The Logger class has the following methods for printing the logging information.

 
All the levels are defined in the org.apache.log4j.Level class and any of the above mentioned method can be called as follows:


import org.apache.log4j.Logger;

public class LogClass {
private static org.apache.log4j.Logger log = Logger.getLogger(LogClass.class);

public static void main(String[] args) {
log.trace("Trace Message!");
log.debug("Debug Message!");
log.info("Info Message!");
log.warn("Warn Message!");
log.error("Error Message!");
log.fatal("Fatal Message!");
}
}

When you compile and run LogClass program it would generate following result:

Debug Message!
Info Message!
Warn Message!
Error Message!
Fatal Message!


log4j - Log Formatting

Apache log4j provides various Layout objects, each of which can format logging data according to various layouts. It is also possible to create a Layout object that formats logging data in an application-specific way.

All Layout objects receive a LoggingEvent object from the Appender objects. The Layout objects then retrieve the message argument from the LoggingEvent and apply the appropriate ObjectRenderer to obtain the String representation of the message.

The Layout Types:

The top-level class in the hierarchy is the abstract class org.apache.log4j.Layout. This is the base class for all other Layout classes in the log4j API.

The Layout class is defined as abstract within an application, we never use this class directly; instead, we work with its subclasses which are as follows:

• DateLayout
HTMLLayout
PatternLayout
• SimpleLayout
• XMLLayout

The Layout Methods:

This class provides a skeleton implementation of all the common operations across all other Layout objects and declares two abstract methods.

Apart from these abstract methods, the Layout class provides concrete implementation for the methods listed below:
 
 
Each subclass can return class-specific information by overriding the concrete implementation of these methods.



log4j - Logging in Console

To write your logging information into a console you would have to use org.apache.log4j.ConsoleAppender.

Following is a sample configuration file log4j.properties for ConsoleAppender.

#set the level of the root logger to DEBUG and set its appender
#as an appender named X

log4j.rootLogger = DEBUG, X

#set the appender named X to be a console appender
log4j.appender.X=org.apache.log4j.ConsoleAppender

#set the layout for the appender X
log4j.appender.X.layout=org.apache.log4j.PatternLayout
log4j.appender.X.layout.conversionPattern=%p-%m%n

Java class is:

import org.apache.log4j.*;

public class ConsoleAppenderExample {
static Logger logger = Logger.getLogger("ConsoleAppenderExample.class");
public static void main(String[] args) {
logger.debug("Content part 1");
logger.debug("Content part 2");
logger.debug("Content part 3");
}
}

After compilation and execution you will get following output on your console.

 
 
log4j - Logging in Files


To write your logging information into a file you would have to use org.apache.log4j.FileAppender. There are following configurable parameters of FileAppender:

FileAppender Configuration:

Following is a sample configuration file log4j.properties for FileAppender.


# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
# Set the name of the file
log4j.appender.FILE.File=${log}/log.out
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, overwrite
log4j.appender.FILE.Append=false
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n

If you love to have an XML configuration file equivalent to above log4j.properties file then here is the content:



Logging in Multiple Files: (RollingFileAppender)

There may be a requirement when you want to write your log message into multiple files for certain reasons like for example if file size reaches to a certain threshold etc.

To write your logging information into multiple files you would have to use org.apache.log4j.RollingFileAppender class which extends the FileAppender class and inherits all its properties.

There are following configurable parameters in addition to what have been mentioned above for FileAppender:



Following is a sample configuration file log4j.properties for RollingFileAppender.


# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
# Set the name of the file
log4j.appender.FILE.File=${log}/log.out
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, should not overwrite
log4j.appender.FILE.Append=true
# Set the maximum file size before rollover
log4j.appender.FILE.MaxFileSize=5KB
# Set the the backup index
log4j.appender.FILE..MaxBackupIndex=2
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n

If you like to have an XML configuration file, you can generate as mentioned in initial section and add only additional paramters related to RollingFileAppender.

This example configuration demonstrates that maximum permissible size of each log file is 5MB. Upon exceeding the maximum size, a new log file will be created and because maxBackupIndex is defined as 2, once the second log file reaches the maximum size, the first log file will be erased and thereafter all the logging information will be rolled back to the first log file.


Daily Log File Generation: (DailyRollingFileAppender)

There may be a requirement when you want to generate your log files on per day basis to keep a clean record of your logging information.

To write your logging information into files on daily basis you would have to use org.apache.log4j.DailyRollingFileAppender class which extends the FileAppender class and inherits all its properties.

There is only one important following configurable parameter in addition to what have been mentioned above for FileAppender:

 
DatePattern controls the rollover schedule using one of the following patterns:


Following is a sample configuration file log4j.properties to generate log files rolling over at midday and midnight of each day.


# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
# Set the name of the file
log4j.appender.FILE.File=${log}/log.out
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, should not overwrite
log4j.appender.FILE.Append=true
# Set the DatePattern
log4j.appender.FILE.DatePattern='.' yyyy-MM-dd-a
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n

If you like to have an XML configuration file, you can generate as mentioned in initial section and add only additional paramters related to DailyRollingFileAppender.



log4j - Logging in Database

The log4j API provides the org.apache.log4j.jdbc.JDBCAppender object, which is capable of putting logging information in a specified database.

JDBCAppender Configuration:

 
Log Table Configuration:


Before you start using JDBC based logging, you shold create a table where all the log information would be maintained. Following is the SQL Statement for Creating the LOGS Table:

CREATE TABLE LOGS
(USER_ID VARCHAR(20) NOT NULL,
DATED DATE NOT NULL,
LOGGER VARCHAR(50) NOT NULL,
LEVEL VARCHAR(10) NOT NULL,
MESSAGE VARCHAR(1000) NOT NULL);

Sample Configuration File:

Following is a sample configuration file log4j.properties for JDBCAppender which will be used to log messages to a LOGS table.

# Define the root logger with appender file
log4j.rootLogger = DEBUG, DB
# Define the DB appender
log4j.appender.DB=org.apache.log4j.jdbc.JDBCAppender
# Set JDBC URL
log4j.appender.DB.URL=jdbc:mysql://localhost/DBNAME
# Set Database Driver
log4j.appender.DB.driver=com.mysql.jdbc.Driver
# Set database user name and password
log4j.appender.DB.user=user_name
log4j.appender.DB.password=password
# Set the SQL statement to be executed.
log4j.appender.DB.sql=INSERT INTO LOGS VALUES('%x','%d','%C','%p','%m')
# Define the layout for file appender
log4j.appender.DB.layout=org.apache.log4j.PatternLayout

Here for a MySQL database, you would have to use actual DBNAME, user id and password where you have created LOGS table. The SQL statement is to execute an INSERT statement with the table name LOGS and values to be entered into the table.

The JDBCAppender does not need a layout to be defined explicitly. Instead, the SQL statement passed to it uses a PatternLayout

If you like to have an XML configuration file equivalent to above log4j.properties file, then here is the content:



Sample Program:

The following Java class is a very simple example that initializes, and then uses, the Log4J logging library for Java applications.

import org.apache.log4j.Logger;
import java.sql.*;
import java.io.*;
import java.util.*;

public class log4jExample{

/* Get actual class name to be printed on */
static Logger log = Logger.getLogger(log4jExample.class.getName());
public static void main(String[] args) throws IOException,SQLException{
log.debug("Debug");
log.info("Info");
}
}

Compilation and Run:

Here are the steps to compile and run the above mentioned program. Make sure you have set PATH and CLASSPATH appropriately before proceeding for the compilation and execution.

All the libraries should be available in CLASSPATH and your log4j.properties file should be available in PATH. So do the following:

1. Create log4j.properties as shown above.
2. Create log4jExample.java as shown above and compile it.
3. Execute log4jExample binary to run the program.

Now check your LOGS table inside DBNAME database and you would find following entries:

 

No comments:

Post a Comment