You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by "Samuel D. Franklin" <sf...@crowechizek.com> on 2002/11/12 23:15:23 UTC
Compressed file recognition for RollingFileAppender
I was using the RollingFileAppender to keep a fairly large number of log
files for an application, and I started to run out of disk space. So I
compressed a bunch of the old files, but then I lost the appender's ability
to rotate out the oldest files. So I gave the appender the ability to
recognize compressed file extensions. I thought the rest of the world might
be able to use this, too, so I figured I'd share. Here's the subclass I
created:
package org.apache.log4j;
import java.io.*;
import java.util.Vector;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.helpers.CountingQuietWriter;
/**
* Allows RollingFileAppender to recognize compressed versions of old
files.
*
* The default list of compression format extensions is {"", ".gz"}. This
may
* be changed by specifying (using the format .gz,.zip,.Z,.bz2) the
* CompressionFormats property for this appender in a config file. Note
that
* the blank extension will be added when the property is read, so is not
* necessary in the config file. Note also that keeping this list short is
* recommended for performance reasons, especially if you also are keeping
* large numbers of backup files.
*
* @author Skip Franklin
*/
public class RollingFileAppenderWithCompression extends RollingFileAppender
{
/**
* The filename extensions of the compression formats supported.
*/
protected String[] compressionFormatList = {"", ".gz"};
/**
The default constructor simply calls its {@link
FileAppender#FileAppender parents constructor}. */
public RollingFileAppenderWithCompression()
{
super();
}
/**
Instantiate an object and open the file designated by
<code>filename</code>. The opened filename will become the ouput
destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file desginated by
<code>filename</code> will be truncated before being opened.
*/
public RollingFileAppenderWithCompression(
Layout layout, String filename, boolean append)
throws IOException
{
super(layout, filename, append);
}
/**
Instantiate a FileAppender and open the file designated by
<code>filename</code>. The opened filename will become the output
destination for this appender.
<p>The file will be appended to. */
public RollingFileAppenderWithCompression(
Layout layout, String filename) throws IOException
{
super(layout, filename);
}
/**
Implements the usual roll over behaviour.
<p>If <code>MaxBackupIndex</code> is positive, then files
{<code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code>}
are renamed to {<code>File.2</code>, ...,
<code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is
renamed <code>File.1</code> and closed. A new <code>File</code> is
created to receive further log output.
<p>If <code>MaxBackupIndex</code> is equal to zero, then the
<code>File</code> is truncated with no backup files created.
Note that this method is not synchronized since doAppend already is.
*/
public void rollOver()
{
File target;
File file;
LogLog.debug("rolling over count=" + ((CountingQuietWriter)
qw).getCount());
LogLog.debug("maxBackupIndex="+maxBackupIndex);
// If maxBackups <= 0, then there is no file renaming to be done.
if(maxBackupIndex > 0)
{
// Delete the oldest file, to keep Windows happy.
file = new File(fileName + '.' + maxBackupIndex);
if (file.exists())
{
file.delete();
}
// Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex,
..., 3, 2}
for (int i = maxBackupIndex - 1; i >= 1; i--)
{
compressedFileLoop:
for (int j = 0; j < compressionFormatList.length; j++)
{
file = new File(fileName + "." + i +
compressionFormatList[j]);
if (file.exists())
{
target = new File(
fileName + '.' + (i + 1) +
compressionFormatList[j]);
LogLog.debug("Renaming file " + file + " to " +
target);
file.renameTo(target);
break compressedFileLoop;
}
}
}
// Rename fileName to fileName.1
target = new File(fileName + "." + 1);
this.closeFile(); // keep windows happy.
file = new File(fileName);
LogLog.debug("Renaming file " + file + " to " + target);
file.renameTo(target);
}
try
{
// This will also close the file. This is OK since multiple
// close operations are safe.
this.setFile(fileName, false, bufferedIO, bufferSize);
}
catch(IOException e)
{
LogLog.error("setFile("+fileName+", false) call failed.", e);
}
}
/** Get access method for list of compression formats. */
public String[] getCompressionFormatList()
{
return compressionFormatList;
}
/** Set access method for list of compression formats. */
public void setCompressionFormatList(String[] newList)
{
compressionFormatList = newList;
}
/** Sets the list of compression formats from a config string. */
public void setCompressionFormats(String inputString)
{
String configString = new String(inputString);
try
{
LogLog.debug("setting compression formats to: " +
configString);
String[] nothing = {""};
if (configString == null || configString.trim().equals(""))
{
setCompressionFormatList(nothing);
return;
}
int commaLoc = configString.indexOf(',');
Vector stuff = new Vector();
stuff.add("");
while (commaLoc != -1)
{
stuff.add(configString.substring(0, commaLoc));
configString = configString.substring(commaLoc+1).trim();
commaLoc = configString.indexOf(',');
}
if (!configString.equals(""))
{
stuff.add(configString);
}
setCompressionFormatList((String[])stuff.toArray(nothing));
}
catch (Exception e)
{
LogLog.error(
"Error setting compression formats (" + inputString + "). "
+
"Error was:" + e);
}
}
}
I considered putting the ability to compress the file during the rollover
in here as well, but decided against it for my application because of the
possible performance impact. I've got a separate process to do the actual
compression that runs during off-peak times. Any comments are appreciated,
and anyone is welcome to re-use this if the spirit moves them.
Skip Franklin
sfranklin@crowechizek.com
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>