Logging is an important part of any application, the only mean to know what’s happened in a production environment before that nasty error. The Java virtual machine took a while to provide a proper logging system (no, System.out is not a proper logging system) and in the meantime an Apache library, Log4J, had become the “de facto” standard for this process.
Although one could think the release of a logging tool in the JDK would start the demise of log4J, it’s not been that way. One reason is that what the JDK provides is a Java Logging API, a layer to link to a real log system (being the Sun system the default one) in a structure similar to Apache Commons Logging, which seems powerful until you realize you won’t often change the chosen log system of a project. The other reason is when you check the documentation you find it lacks some of the ease of use and capabilities that have made Log4J what it is.
Log4J is really easy to set up, at least for the most common usage: writing a rolling file that store the daily output of your application. Thing is I always find myself “Googling” for those configuration files and the pages with relevant information, so I’ve thought it would save me some time to collect here all that information. Here I would talk about two tools, Log4j and Chainsaw.
Log4J
Log4J is the logging library from Apache. Current version is 1.2, with version 1.3 no longer being developed and version 2.0 being an experimental library to use Java 5 capabilities within logging. This section will talk about log4J 1.2 and will focus in a simple scenario: logging into a daily log in the same file system.
First a bit of theory. Log4J has two main components: loggers and appenders. A logger is responsible of logging the events. There’s always a rootLogger and we can define as many loggers as we need, usually on a package basis. Loggers accept inheritance (although out of scope of this post).
An appender is a destination of the messages sent to the logger. One logger can have several appenders related to it, and all of them will receive the messages. An appender can write the messages into a file, send them through the network or show then in the console. All appenders have a related layout that tells the class how to format the message. You can find the format configuration keys here.
Log4J has 6 logging levels: TRACE, DEBUG, INFO, WARN, ERROR and FATAL. Each one has a priority so when you set up a logging level of TRACE you will see all messages while a logging level of WARN will only show WARN, ERROR and FATAL.
Onto the usage part: first of all you need to copy the Log4J jar (available here) on the lib folder (or any other folder in the Classpath) of your application. The configuration file (log4j.properties) must also be placed in the Classpath of the application.
You can use this as an example of a properties (log4j.properties) configuration file:
# Root logger uses debug level and 2 appenders named stdout and R
log4j.rootLogger=debug, stdout, R
# Print only messages of level WARN or above in the package com.foo, using root logger
log4j.logger.com.foo=WARN
# Declaring first appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller’s file name and line number.
# sample output: INFO [main] (MyApp2.java:12) – Entering application.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) – %m%n
# Declaring second appender
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log
log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c – %m%n
# Declaring a third appender, not used right now
log4j.appender.dest1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dest1.DatePattern=’.'yyyy-MM-dd
log4j.appender.dest1.Threshold=info
log4j.appender.dest1.File=info.log
log4j.appender.dest1.layout=org.apache.log4j.PatternLayout
log4j.appender.dest1.layout.ConversionPattern=%d [%t: %C.%M:%L] %p: %m%n
# Declaring a new logger for the package com.myco that uses the third appender
log4j.logger.com.myco=DEBUG, dest1
To make the logger available to your class you should declare it as shown here:
import org.apache.log4j.Logger;
public class MyClass {
final static Logger logger = Logger.getLogger(MyClass.class.getName());
MyClass() {
}
public void foo() {
logger.debug(“Hello world.”);
…
}
}
As you can see the logger variable (which I usually name “log”) is a final static variable that will be shared between all the object. Don’t worry, Log4J is thread safe. You can notice we pass the name of the class as parameter to the getLogger method. This allows us to identify the origin of the message quite easily in the log file, and ensures each log object is unique.
To add a new entry to the log file, you can use:
log.debug(“Message”);
log.debug(“Message”, new Throwable());
You may change debug by any of the other levels of logging as appropriate. Every level has two versions of the method, one that accepts only a message and one that also accepts a Throwable object, so you can pass exceptions into the log file.
A recommended way to improve the performance of the system is to check if the log level is enabled before calling the corresponding method, as you can see next:
if(log.isDebugEnabled()){
log.debug(“Message”);
}
if(log.isInfoEnabled()){
log.info(“Message”);
}
if(log.isTraceEnabled()){
log.trace(“Message”);
}
This avoid the system to build a log message that later on will be discarded by the logger due to the level not being logged, saving several cpu cycles.
You have a free small manual of Log4J 1.2 here. If you need more information on Log4J 1.2 or need to use it in a more complex scenario check this commercial book that provides a detailed explanation.
Chainsaw
Chainsaw is a companion application to Log4j written by members of the Log4j development community. It provides a GUI interface that parses Log4J logs and allows you to see the most relevant lines of it, like rrors, etc. The latest release if from 2006, but it should still work with your log files.