HOWTO: Using Apache's Log4j RollingFileAppender, An Example

| No TrackBacks
I recently wrestled with Log4j's RollingFileAppender, which lets you automatically rotate your application's log files once they reach a certain size.  Automatically rotating log files are important for distributed applications so your logs don't fill up a user's PC, or waste server disk space unnecessarily.  After putting all of the Log4j pieces together, I finally got things working as desired and thought it might be nice to share my success with the world.

Here's the complete source to the example.

/**
* Copyright (c) 2009 Mark S. Kolich
* http://mark.koli.ch
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

package org.kolich.log4j;

import java.io.File;
import java.util.Date;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;

public class RollingFileAppenderExample {

// The default log level is INFO.
private static final Level DEFAULT_LOGGER_LEVEL = Level.INFO;

private static final String LOG_DIR = "log";
private static final String LOG_FILENAME = "my.log";

private static final String FILE_SEPARATOR_PROP = "file.separator";
private static final String SYSTEM_OUT = "System.out";

// This is the pattern that Log4j will use when logging:
// %d{ISO8601} %5p %c{1}:%L - %m%n
private static final String LOG_PATTERN = "%d{ISO8601} %5p [%l] - %m%n";

// Set the maximum size that each log file is allowed to reach before being
// rolled over to backup files. In configuration files, the MaxFileSize option
// takes an long integer in the range 0 - 2^63. You can specify the value with
// the suffixes "KB", "MB" or "GB" so that the integer is interpreted being
// expressed respectively in kilobytes, megabytes or gigabytes. For example,
// the value "10KB" will be interpreted as 10240.
private static final int MAX_LOG_BACKUP_FILES = 200;
private static final String MAX_LOG_FILE_SIZE = "128KB";
private static final int LOG_IO_BUFFER_SIZE_BYTES = 1024;

// We use the root logger for everything so we can capture all of the output
// from shared libraries that use Log4j too
public static final Logger logger = Logger.getRootLogger();
static {
try {

// Where the logs will go.
final File logDir = new File( LOG_DIR );

// Try to create the default log directory.
logDir.mkdirs();

final File logFile = new File( logDir,
String.format("%s%s",
System.getProperty(FILE_SEPARATOR_PROP),
LOG_FILENAME) );

// Create a new pattern layout with our requested log pattern.
final PatternLayout pl = new PatternLayout( LOG_PATTERN );

// Setup the rolling log file appender. Note the last arg, true,
// which tells this RollingFileAppender to append to existing logs
// instead of overwriting what's already there.
final RollingFileAppender rfp = new RollingFileAppender( pl,
logFile.getCanonicalPath(),
true );

// We want the logger to flush its output to the log file
// stream immeaditely; if you don't have this set, then
// Log4j will buffer the log file output which isn't ideal.
rfp.setImmediateFlush( true );
rfp.setBufferedIO( false );
rfp.setBufferSize( LOG_IO_BUFFER_SIZE_BYTES );

// Set the Max number of files and max size of each log
// file to keep around.
rfp.setMaxBackupIndex( MAX_LOG_BACKUP_FILES );
rfp.setMaxFileSize( MAX_LOG_FILE_SIZE );

// Set the default level of this logger.
logger.setLevel( DEFAULT_LOGGER_LEVEL );

// This logger will use the rolling appender.
logger.addAppender( rfp );

// Also log to the console so we can see what's going on.
final ConsoleAppender cp = new ConsoleAppender( pl, SYSTEM_OUT );
cp.setImmediateFlush( true );
logger.addAppender( cp );

}
catch ( Exception e ) {
// If something bad happened, log the exception
// to System.err
e.printStackTrace( System.err );
}
}

/**
* Usage examples.
*
* @param args
*/
public static void main ( String [] args ) {

// Log an info message.
logger.info( "Some info message" );

// Log an error
logger.error( "Ouch, something bad happened." );

// Trace and debug messages, note that these WONT show up
// because the default logging level is
// INFO. If you want to see these types of messages
// then you should set the DEFAULT_LOGGER_LEVEL to
// Level.TRACE or Level.DEBUG
logger.debug( "A debug message; DEFAULT_LOGGER_LEVEL = Level.INFO" );
logger.trace( "A trace message; DEFAULT_LOGGER_LEVEL = Level.INFO" );

// Log a bunch of random stuff, this should force the log file
// to roll over at least a few times.
for(int i = 0; i < 5000; i++){
logger.info( "Epoch is " + new Date().getTime() );
}

// Foo bar fatal
logger.fatal( "Foo bar" );

logger.info( "Example ran successfully" );

}

}

Did You Find this Helpful?

Did you find this post helpful, or at least, interesting?

  

About Mark

A Silicon Valley native, Mark Kolich is a full-time Software Engineer and a consultant for hire. A web technologies expert, his current focus is on building powerful and robust cloud-driven web-applications using Java, PHP, Perl, AJAX, DHTML, CSS, and JavaScript. His favorite programming languages are PHP, Java and JavaScript. He uses Linux, enjoys biking to work, loves building great software, and always writes elegant, readable, and maintainable code.

No TrackBacks

No trackbacks attached to this entry.

Twitter (@markkolich)

Translate

About this Entry

This page contains a single entry by Mark Kolich published on August 28, 2009 3:00 PM.

Mount San Gorgonio: Hike To the Summit and Back in a Single Day was the previous entry in this blog.

HOWTO: Implement a URL Pattern Interpreter Similar to Django and RoR in PHP (Drop the .php With mod_rewrite) is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.