We had the same problem. The issue is down to the way log-rollover works. It is consistently overwriting old log files hence there are gaps in the data.
The code lists the log files to find the most recent. It assumes that the most recent log file is at the end of the list. This isn’t guarenteed to be true. It seems to work fine on Windows but consistently fails on Linux.
In more detail: The file: org.jivesoftware.openfire.audit.spi.AuditorImpl.java, line 276 does this:
File[] files = baseFolder.listFiles(filter);
Then line 283 does this to determine the most recent file and hence work out the next log file number to use.
File lastFile = files[http://files.length - 1|http://files.length - 1];
However, the javadoc for File.listFiles() states
“There is no guarantee that the name strings in the resulting array will appear in any specific order; they are not, in particular, guaranteed to appear in alphabetical order.”
So, on Linux the code retrieves a log file that is not the latest (say 001.log), increments the log number (to say 002) and thus overwrites 002.log with newer data. This gives you the gaps you see.
The simplest fix is to add the following code before line 283:
// File implements Comparable as a lexographical ordering of abstract
// path names. Arrays.sort() uses the Comparable interface. So this shoul
// give us an alpha sorted array of files. This is ok, because the fil
// name format is such that an alpha sort will produce a date sort + log+
// number sort. We want a date + log number sort so that the next line of++
// code after this one retrieves the most last log file in the sequence
// Without this fix, on Linux, the list of log files is not guarentee
// to be in the correct order Arrays.sort(files);
A more robust solution might be to write code that explicitly finds the largest log file number rather than relying on an alpha sort. Or, remove the rollover code entirely and just use log4j instead - although AFAIK this doesn’t support Openfire’s exact log rollover policy.
Looking at the rest of the code base, there doesn’t seem to be any other similar mis-use of File.listFiles() although the class-loaders (JiveClassLoader and PluginClassLoader) use it which might cause different versions of the same class to be loaded on different platforms.
Code to demonstrate the problem:
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays; public class FileListTest
{
// arg0 is log directory, arg1 is a date e.g. 20071206
public static void main( String[] args )
{
File baseFolder = new File( args[0] );
final String filePrefix = "jive.audit-" + args[1]; // orig code
FilenameFilter filter = new FilenameFilter( )
{
public boolean accept( File dir, String name )
{
return name.startsWith( filePrefix ) && name.endsWith( ".log" );
}
};
File[] files = baseFolder.listFiles( filter );
// orig code end // Take a copy of the file list for later comparison
File[] unsortedList = new File[http://files.length|http://files.length];
System.arraycopy( files, 0, unsortedList, 0, files.length ); Arrays.sort( files ); // Fix code // Print unsorted vs sorted. Note differences with an arrow.
for ( int i = 0; i < unsortedList.length; i++ )
{
System.out.print( unsortedList[i] + " " + files[i] );
if ( !unsortedList[i].equals( files[i] ) )
{
System.out.print( " <-----" );
}
System.out.print( "\n" );
}
}
}
Example usage:
java FileListTest /opt/openfire/logs 20071205
/opt/openfire/logs/jive.audit-20071205-000.log /opt/openfire/logs/jive.audit-20071205-000.log
/opt/openfire/logs/jive.audit-20071205-001.log /opt/openfire/logs/jive.audit-20071205-001.log
/opt/openfire/logs/jive.audit-20071205-003.log /opt/openfire/logs/jive.audit-20071205-002.log <-----
/opt/openfire/logs/jive.audit-20071205-002.log /opt/openfire/logs/jive.audit-20071205-003.log <-----
LHS show the default list order returned from listFiles(), RHS shows it sorted. Lines marked with an arrow show differences which would result in log file gaps