[Jukebox-cvs] CVS update: J4/src/java/gnu/j4/core FileSyslog.java LogConfigKeywords.java
Brought to you by:
vtt
From: CVS B. <vt...@fr...> - 2000-08-31 07:29:01
|
User: vt Date: 00/08/31 00:28:57 Modified: src/java/gnu/j4/core FileSyslog.java LogConfigKeywords.java Log: Added the log rotation. So far, it's just size based, but enough for the practical purposes. Revision Changes Path 1.4 +244 -19 J4/src/java/gnu/j4/core/FileSyslog.java CVSWEB Options: ------------------- CVSWeb: Annotate this file: http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/J4/src/java/gnu/j4/core/FileSyslog.java?annotate=1.4&cvsroot=jukebox4 CVSWeb: View this file: http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/J4/src/java/gnu/j4/core/FileSyslog.java?rev=1.4&content-type=text/x-cvsweb-markup&cvsroot=jukebox4 CVSWeb: Diff to previous version: http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/J4/src/java/gnu/j4/core/FileSyslog.java.diff?r1=1.4&r2=1.3&cvsroot=jukebox4 ----------------------------------- Index: FileSyslog.java =================================================================== RCS file: /usr/local/cvs/J4/src/java/gnu/j4/core/FileSyslog.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- FileSyslog.java 2000/07/24 06:42:08 1.3 +++ FileSyslog.java 2000/08/31 07:28:56 1.4 @@ -1,8 +1,11 @@ package gnu.j4.core; +import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; /** * Syslog with the file output. @@ -19,12 +22,17 @@ * The {@link #write write()} method looks really weird because it's being * called before the actual construction of the object is completed ;-) * - * @author Copyright © <a href="mailto:vt...@fr...">Vadim Tkachenko</a> 1998 - * @version $Id: FileSyslog.java,v 1.3 2000/07/24 06:42:08 vt Exp $ + * @author Copyright © <a href="mailto:vt...@fr...">Vadim Tkachenko</a> 1998-2000 + * @version $Id: FileSyslog.java,v 1.4 2000/08/31 07:28:56 vt Exp $ */ public class FileSyslog extends BasicSyslog implements LogLevels, LogConfigKeywords { /** + * File to write the log to. + */ + protected File target; + + /** * Stream to write to. */ protected PrintWriter out; @@ -35,6 +43,39 @@ protected SimpleQueue deferred; /** + * Maximum size allowed for the output file, in bytes. + * + * Zero value means no limits (no rotation, either). + */ + protected long maxSize; + + /** + * Current size of the log file. + * + * Actually, the sum of the lenghts of all the records logged since this + * counter was reset (on instantiation or rotation). Gets adjusted on + * instantiation if the file already exists. + */ + protected long currentSize = 0; + + /** + * Maximum age allowed for the output file, in seconds. + * + * Zero value means no limits (no rotation, either). + */ + protected long maxAge; + + /** + * String that defines the name of the rotated file. + */ + protected String suffixFormat; + + /** + * Used to compose the suffix of the rotated file. + */ + protected SimpleDateFormat suffixFormatter; + + /** * Create the instance. * * Get the {@link LogConfigKeywords#SYSLOG_FILE file name} from the @@ -44,35 +85,146 @@ * the file specified in the configuration. */ public FileSyslog() throws InstantiationException { + super(); - - init(conf.getString(SYSLOG_FILE)); - + init(conf.getString(SYSLOG_FILE_NAME), + conf.getLong(SYSLOG_FILE_MAXSIZE, 0), + conf.getLong(SYSLOG_FILE_MAXAGE, 0), + conf.getString(SYSLOG_FILE_SUFFIX, SYSLOG_FILE_SUFFIX_DEFAULT)); } /** * Create the instance writing to the specified log file. + * + * @param outputFileName Name of the file to write the log to. + * + * @param maxSize Maximum allowed file size, in bytes, before the log + * has to be rotated. Zero value means no size rotation. * - * @param outputFileName File to write the log to. + * @param maxAge Maximum allowed time, in seconds, before the log has to + * be rotated. Zero value means no time rotation. * + * @param suffixFormat How the suffix is going to look like. + * * @exception InstantiationException if it is not possible to write to * the file specified in the configuration. */ - public FileSyslog(String outputFileName) throws InstantiationException { + public FileSyslog(String outputFileName, long maxSize, long maxAge, String suffixFormat) throws InstantiationException { super(); - init(outputFileName); + init(outputFileName, maxSize, maxAge, suffixFormat); } /** - * Actually open the file. + * Actually open the file and configure the rotation, if required. + * + * @param outputFileName Name of the file to write the log to. + * + * @param maxSize Maximum allowed file size, in bytes, before the log + * has to be rotated. Zero value means no size rotation. + * + * @param maxAge Maximum allowed time, in seconds, before the log has to + * be rotated. Zero value means no time rotation. + * + * @param suffixFormat How the suffix is going to look like. + * + * @exception InstantiationException if it is not possible to write to + * the file specified in the configuration. */ - private void init(String outputFileName) throws InstantiationException { + private void init(String outputFileName, long maxSize, long maxAge, String suffixFormat) throws InstantiationException { + + this.maxSize = maxSize; + this.maxAge = maxAge; + this.suffixFormat = suffixFormat; + suffixFormatter = new SimpleDateFormat(suffixFormat); try { - out = new PrintWriter(new FileOutputStream(outputFileName)); + // Check if the formatter is OK + + suffixFormatter.format(new Date(System.currentTimeMillis())); + + } catch ( Throwable t ) { + + // Shit, they've screwed up! + + String message = SYSLOG_FILE_SUFFIX + + " (" + + conf.getString(SYSLOG_FILE_SUFFIX) + + ") is invalid (" + + t.getMessage() + + "), using default (" + + SYSLOG_FILE_SUFFIX_DEFAULT + + ")"; + + Logger.log(Thread.currentThread(), this, LOG_WARNING, Logger.LOG_LOGGER, message, null); + + // We don't have a right to screw up on this one! + + this.suffixFormat = SYSLOG_FILE_SUFFIX_DEFAULT; + suffixFormatter = new SimpleDateFormat(this.suffixFormat); + } + + if ( maxSize != 0 ) { + + logMessage(new LogRecord(Thread.currentThread(), + this, + LOG_NOTICE, + Logger.LOG_LOGGER, + "The file will be rotated if exceeds " + + maxSize + + " bytes, suffix is '" + + suffixFormat + + "'", + null)); + } + try { + + // This variable will be set to true if the old log exists and + // has to be appended to. + + boolean append = false; + + // First of all, let's see if we have to rotate it + + target = new File(outputFileName); + + if ( target.exists() ) { + + // OK, we do have to do something about it. We wouldn't + // rotate the log based on time, though. + + if ( maxSize != 0 ) { + + if ( target.length() >= maxSize ) { + + // OK, have to rotate... + + doRotate(); + + } else { + + currentSize += target.length(); + append = true; + + } + + } else { + + + // Well, since it does exist and we didn't have to + // rotate it, let's append, then + + append = true; + } + + } + + // OK, by now it's supposed to be rotated already. + + out = new PrintWriter(new FileOutputStream(target.toString(), append)); + } catch ( IOException ioex ) { Logger.logTo(null); @@ -94,26 +246,99 @@ if ( out == null ) { - // This bizarre situation (with both 'out' and 'deferred) - // happens because this method is called before the actual - // construction is being done, not because I'm stupid and forgot - // to create the objects in the constructor or in the + // VT: NOTE: This bizarre situation (with both 'out' and + // 'deferred') happens because this method is called before the + // actual construction is being done, not because I'm stupid and + // forgot to create the objects in the constructor or in the // declaration. if ( deferred == null ) { deferred = new SimpleQueue(); } + deferred.put(message); } else { - while ( !deferred.isEmpty() ) { - out.println(deferred.get().toString()); + synchronized ( this ) { + while ( !deferred.isEmpty() ) { + + String deferredMessage = deferred.get().toString(); + + out.println(deferredMessage); + + currentSize += deferredMessage.length(); + } + + out.println(message); + out.flush(); + + currentSize += message.length(); + + // We've allowed some slack to write the deferred messages, but + // it shouldn't matter too much since the only case it exists at + // all is at the startup. + + // Now it's time to check if we have to rotate the log. + + if ( maxSize != 0 && currentSize >= maxSize ) { + + rotate(); + } } + } + } + + /** + * Rotate the output file. + * + * This is a wrapper for the {@link #doRotate actual rotation call}. It + * closes the output stream before rotating and reopend it after. + */ + private void rotate() { + + long start = System.currentTimeMillis(); + + // No need to flush, we've just done it + + out.close(); + doRotate(); + + try { + + init(target.toString(), maxSize, maxAge, suffixFormat); - out.println(message); - out.flush(); + } catch ( Throwable t ) { + + System.err.println("This is quite unlikely and bizarre, don't know how to handle:"); + t.printStackTrace(); } + + logMessage(new LogRecord(Thread.currentThread(), + this, + LOG_NOTICE, + Logger.LOG_LOGGER, + "Rotation complete in " + + (System.currentTimeMillis()-start) + + "ms", + null)); + } + + /** + * Rotate the output file. + * + * <strong>IMPORTANT:</strong> the output file must not be open, + * otherwise we have a resource leak (on UNIX) or sharing violation (on + * Windows). + */ + private void doRotate() { + + File rotated = new File(target.toString() + + "." + + suffixFormatter.format(new Date(System.currentTimeMillis()))); + + target.renameTo(rotated); + currentSize = 0; } } 1.10 +27 -3 J4/src/java/gnu/j4/core/LogConfigKeywords.java CVSWEB Options: ------------------- CVSWeb: Annotate this file: http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/J4/src/java/gnu/j4/core/LogConfigKeywords.java?annotate=1.10&cvsroot=jukebox4 CVSWeb: View this file: http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/J4/src/java/gnu/j4/core/LogConfigKeywords.java?rev=1.10&content-type=text/x-cvsweb-markup&cvsroot=jukebox4 CVSWeb: Diff to previous version: http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/J4/src/java/gnu/j4/core/LogConfigKeywords.java.diff?r1=1.10&r2=1.9&cvsroot=jukebox4 ----------------------------------- Index: LogConfigKeywords.java =================================================================== RCS file: /usr/local/cvs/J4/src/java/gnu/j4/core/LogConfigKeywords.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- LogConfigKeywords.java 1999/06/29 04:35:34 1.9 +++ LogConfigKeywords.java 2000/08/31 07:28:56 1.10 @@ -4,8 +4,8 @@ * Basic set of string constants used in the log system configuration. * <p> * See the source code for exact values. - * @author Copyright © <a href="mailto:vt...@fr...">Vadim Tkachenko</a> 1998 - * @version $Id: LogConfigKeywords.java,v 1.9 1999/06/29 04:35:34 vt Exp $ + * @author Copyright © <a href="mailto:vt...@fr...">Vadim Tkachenko</a> 1998-2000 + * @version $Id: LogConfigKeywords.java,v 1.10 2000/08/31 07:28:56 vt Exp $ */ public interface LogConfigKeywords { /** @@ -121,5 +121,29 @@ * Configuration keyword to retrieve the file name for {@link FileSyslog * FileSyslog}. */ - public static final String SYSLOG_FILE = "syslog.file"; + public static final String SYSLOG_FILE_NAME = "syslog.file.name"; + + /** + * Configuration keyword to retrieve the maximum size allowed for the + * {@link FileSyslog FileSyslog} output file. + */ + public static final String SYSLOG_FILE_MAXSIZE = "syslog.file.maxsize"; + + /** + * Configuration keyword to retrieve the maximum age allowed for the + * {@link FileSyslog FileSyslog} output file. + */ + public static final String SYSLOG_FILE_MAXAGE = "syslog.file.maxage"; + + /** + * Configuration keyword to retrieve the rotation suffix for {@link + * FileSyslog FileSyslog} output file. It has to be formatted according + * to the requirements of <code>java.text.SimpleDateFormat</code> class. + */ + public static final String SYSLOG_FILE_SUFFIX = "syslog.file.suffix"; + + /** + * Default {@link FileSyslog syslog file} rotation suffix format. + */ + public static final String SYSLOG_FILE_SUFFIX_DEFAULT = "yyyy.MM.dd-hh:mm:ss"; } |