Tuesday, October 21, 2008

Log4J tips.

I've been in the Java world for just over a year now. I've been mostly busy trying to learn all of the different technologies that are needed to get my job done. Some of them have well documented places online to go and find information, others are harder to understand and require much more digging. To make it easier on some other people, I'm trying to pass on some of the things that I've had to learn to get started.

We use Log4J (log4j-1.2.8.jar) as the tool for our logging. I don't know why we don't use built in java logging, I can't say if it's better or not, but all of the projects already were using Log4J. I was going to have to learn it in order to maintain existing applications, I may as well use it as well.

Log4J is the logging tool written by the Apache group. The Log4J manual is pretty good, unfortunately I didn't find it until after I had stumbled my way through some problems.

In our projects everything was using a static logger. With my C background I had to get used to the fact that this actually meant only one logger per Class, rather than one per instance.
static Logger logger = Logger.getLogger(CustomerBusiness.class);

Next, the log4j.properties file is used to control everything. It can be done via code, but it's better to keep it separate.

Logging is inherited and all of the classes inherit from rootLogger.
log4j.rootLogger=DEBUG, CONSOLE

The above setting sets the default level of logging to be for all messages of DEBUG and higher,
with output going to the CONSOLE object. The console configuration will be shown below.

There were some times that I had one of my classes spitting out more logging than I needed at the time. In order to limit one class's logging the level for that class can be changed with an additional line in the configuration.
log4j.logger.net.sr.project.customerData=INFO,CONSOLE

This will increase the level of logging for my customerData object to be Info and higher, which will ignore all of the logger.debug statements. Also if there is a class under the path customerData, maybe there is a helper clas that is net.sr.project.customerData.datahelper, that too would get the Info level of logging.

In order to configure the console appender in your log4j.properties file.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-5p %c - %m%n


This is a console appender because it user org.apache.log4j.ConsoleAppender. The name CONSOLE, both here and in the above configuration is arbitrary, it could just as easily be name FRED. This CONSOLE object also configured the output and what it will look like. You can read more about the Pattern Layout if you want. I pretty much just keep the same one.


Another good appender is the Rolling File. This has the ability to limit the size of a file, and will create a new file daily. Having a new file daily is a huge benefit, because old data can more easily be searched, zipped, archived, or deleted. If you are going to write data to a file I definitely suggest using the rolling file. Here is the rolling file configuration.

log4j.appender.ROLLING_FILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ContextPrinting=enabled
log4j.appender.ROLLING_FILE.File=/opt/logs/myProjectt_log4j.log
log4j.appender.ROLLING_FILE.layout.ConversionPattern=%d{ISO8601} %-5p %c - %m%n
log4j.appender.ROLLING_FILE.DatePattern='.'yyyy-MM-dd

One note of warning. Errors will be thrown from logging if there is an error. Logging an object that is null with throw a null pointer exception, even if the logging level is set to higher.

For example.
Interger age = null;
logger.debug(age); // this will throw a null pointer exception.

No comments: