From: <fg...@us...> - 2008-01-26 13:53:17
|
Revision: 544 http://openutils.svn.sourceforge.net/openutils/?rev=544&view=rev Author: fgiust Date: 2008-01-26 05:53:20 -0800 (Sat, 26 Jan 2008) Log Message: ----------- new EnhancedDailyRollingFileAppender Modified Paths: -------------- trunk/openutils-log4j/src/site/apt/index.apt Added Paths: ----------- trunk/openutils-log4j/src/main/java/it/openutils/log4j/EnhancedDailyRollingFileAppender.java trunk/openutils-log4j/src/site/apt/fileppenders.apt Added: trunk/openutils-log4j/src/main/java/it/openutils/log4j/EnhancedDailyRollingFileAppender.java =================================================================== --- trunk/openutils-log4j/src/main/java/it/openutils/log4j/EnhancedDailyRollingFileAppender.java (rev 0) +++ trunk/openutils-log4j/src/main/java/it/openutils/log4j/EnhancedDailyRollingFileAppender.java 2008-01-26 13:53:20 UTC (rev 544) @@ -0,0 +1,398 @@ +package it.openutils.log4j; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + +import org.apache.log4j.FileAppender; +import org.apache.log4j.Layout; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.spi.LoggingEvent; + + +/** + * Enhanced version of standard DailyRollingFileAppender that allow moving rotated files to a different directory. You + * can configure the target directory by setting the <code>archiveDirectory</code> property. The default value is + * <code>archive</code> <strong>Note that since DailyRollingFileAppender is not easily extendible, this class is + * actually a copy and paste of all the code with slights modifications...</strong> + * @author fgiust + * @version $Id: $ + */ +public class EnhancedDailyRollingFileAppender extends FileAppender +{ + + // The code assumes that the following constants are in a increasing + // sequence. + static final int TOP_OF_TROUBLE = -1; + + static final int TOP_OF_MINUTE = 0; + + static final int TOP_OF_HOUR = 1; + + static final int HALF_DAY = 2; + + static final int TOP_OF_DAY = 3; + + static final int TOP_OF_WEEK = 4; + + static final int TOP_OF_MONTH = 5; + + /** + * The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. + */ + private String datePattern = "'.'yyyy-MM-dd"; + + /** + * The log file will be renamed to the value of the scheduledFilename variable when the next interval is entered. + * For example, if the rollover period is one hour, the log file will be renamed to the value of "scheduledFilename" + * at the beginning of the next hour. The precise time when a rollover occurs depends on logging activity. + */ + private String scheduledFilename; + + String archiveDirectory = "archive"; + + /** + * The next time we estimate a rollover should occur. + */ + private long nextCheck = System.currentTimeMillis() - 1; + + Date now = new Date(); + + SimpleDateFormat sdf; + + RollingCalendar rc = new RollingCalendar(); + + int checkPeriod = TOP_OF_TROUBLE; + + // The gmtTimeZone is used only in computeCheckPeriod() method. + static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT"); + + /** + * The default constructor does nothing. + */ + public EnhancedDailyRollingFileAppender() + { + } + + /** + * Instantiate a <code>DailyRollingFileAppender</code> and open the file designated by <code>filename</code>. + * The opened filename will become the ouput destination for this appender. + */ + public EnhancedDailyRollingFileAppender(Layout layout, String filename, String datePattern) throws IOException + { + super(layout, filename, true); + this.datePattern = datePattern; + activateOptions(); + } + + /** + * Sets the archiveDirectory. + * @param archiveDirectory the archiveDirectory to set + */ + public void setArchiveDirectory(String archiveDirectory) + { + this.archiveDirectory = archiveDirectory; + } + + /** + * The <b>DatePattern</b> takes a string in the same format as expected by {@link SimpleDateFormat}. This options + * determines the rollover schedule. + */ + public void setDatePattern(String pattern) + { + datePattern = pattern; + } + + /** Returns the value of the <b>DatePattern</b> option. */ + public String getDatePattern() + { + return datePattern; + } + + public void activateOptions() + { + super.activateOptions(); + if (datePattern != null && fileName != null) + { + now.setTime(System.currentTimeMillis()); + sdf = new SimpleDateFormat(datePattern); + int type = computeCheckPeriod(); + printPeriodicity(type); + rc.setType(type); + File file = new File(fileName); + scheduledFilename = fileName + sdf.format(new Date(file.lastModified())); + + } + else + { + LogLog.error("Either File or DatePattern options are not set for appender [" + name + "]."); + } + } + + void printPeriodicity(int type) + { + switch (type) + { + case TOP_OF_MINUTE : + LogLog.debug("Appender [" + name + "] to be rolled every minute."); + break; + case TOP_OF_HOUR : + LogLog.debug("Appender [" + name + "] to be rolled on top of every hour."); + break; + case HALF_DAY : + LogLog.debug("Appender [" + name + "] to be rolled at midday and midnight."); + break; + case TOP_OF_DAY : + LogLog.debug("Appender [" + name + "] to be rolled at midnight."); + break; + case TOP_OF_WEEK : + LogLog.debug("Appender [" + name + "] to be rolled at start of week."); + break; + case TOP_OF_MONTH : + LogLog.debug("Appender [" + name + "] to be rolled at start of every month."); + break; + default : + LogLog.warn("Unknown periodicity for appender [" + name + "]."); + } + } + + // This method computes the roll over period by looping over the + // periods, starting with the shortest, and stopping when the r0 is + // different from from r1, where r0 is the epoch formatted according + // the datePattern (supplied by the user) and r1 is the + // epoch+nextMillis(i) formatted according to datePattern. All date + // formatting is done in GMT and not local format because the test + // logic is based on comparisons relative to 1970-01-01 00:00:00 + // GMT (the epoch). + + int computeCheckPeriod() + { + RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.ENGLISH); + // set sate to 1970-01-01 00:00:00 GMT + Date epoch = new Date(0); + if (datePattern != null) + { + for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) + { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern); + simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT + String r0 = simpleDateFormat.format(epoch); + rollingCalendar.setType(i); + Date next = new Date(rollingCalendar.getNextCheckMillis(epoch)); + String r1 = simpleDateFormat.format(next); + if (r0 != null && r1 != null && !r0.equals(r1)) + { + return i; + } + } + } + return TOP_OF_TROUBLE; // Deliberately head for trouble... + } + + /** + * Rollover the current file to a new file. + */ + void rollOver() throws IOException + { + + /* Compute filename, but only if datePattern is specified */ + if (datePattern == null) + { + errorHandler.error("Missing DatePattern option in rollOver()."); + return; + } + + String datedFilename = fileName + sdf.format(now); + // It is too early to roll over because we are still within the + // bounds of the current interval. Rollover will occur once the + // next interval is reached. + if (scheduledFilename.equals(datedFilename)) + { + return; + } + + // close current file, and rename it to datedFilename + this.closeFile(); + + File scheduledFile = new File(scheduledFilename); + File targetDir; + if (archiveDirectory != null) + { + targetDir = new File(scheduledFile.getParentFile(), archiveDirectory); + } + else + { + targetDir = scheduledFile.getParentFile(); + } + if (!targetDir.exists()) + { + boolean newdir = targetDir.mkdirs(); + if (!newdir) + { + LogLog.error("Failed to create dir [" + targetDir.getAbsolutePath() + "]."); + } + } + + File target = new File(targetDir, scheduledFile.getName()); + + if (target.exists()) + { + target.delete(); + } + + File file = new File(fileName); + boolean result = file.renameTo(target); + if (result) + { + LogLog.debug(fileName + " -> " + scheduledFilename); + } + else + { + LogLog.error("Failed to rename [" + fileName + "] to [" + target.getAbsolutePath() + "]."); + + // try without moving: + target = new File(scheduledFilename); + result = file.renameTo(target); + if (result) + { + LogLog.debug(fileName + " -> " + scheduledFilename); + } + else + { + LogLog.error("Failed to rename [" + fileName + "] to [" + scheduledFilename + "]."); + } + } + + try + { + // This will also close the file. This is OK since multiple + // close operations are safe. + this.setFile(fileName, false, this.bufferedIO, this.bufferSize); + } + catch (IOException e) + { + errorHandler.error("setFile(" + fileName + ", false) call failed."); + } + scheduledFilename = datedFilename; + } + + /** + * This method differentiates DailyRollingFileAppender from its super class. + * <p> + * Before actually logging, this method will check whether it is time to do a rollover. If it is, it will schedule + * the next rollover time and then rollover. + */ + protected void subAppend(LoggingEvent event) + { + long n = System.currentTimeMillis(); + if (n >= nextCheck) + { + now.setTime(n); + nextCheck = rc.getNextCheckMillis(now); + try + { + rollOver(); + } + catch (IOException ioe) + { + LogLog.error("rollOver() failed.", ioe); + } + } + super.subAppend(event); + } +} + + +/** + * RollingCalendar is a helper class to DailyRollingFileAppender. Given a periodicity type and the current time, it + * computes the start of the next interval. + */ +class RollingCalendar extends GregorianCalendar +{ + + int type = EnhancedDailyRollingFileAppender.TOP_OF_TROUBLE; + + RollingCalendar() + { + super(); + } + + RollingCalendar(TimeZone tz, Locale locale) + { + super(tz, locale); + } + + void setType(int type) + { + this.type = type; + } + + public long getNextCheckMillis(Date now) + { + return getNextCheckDate(now).getTime(); + } + + public Date getNextCheckDate(Date now) + { + this.setTime(now); + + switch (type) + { + case EnhancedDailyRollingFileAppender.TOP_OF_MINUTE : + this.set(Calendar.SECOND, 0); + this.set(Calendar.MILLISECOND, 0); + this.add(Calendar.MINUTE, 1); + break; + case EnhancedDailyRollingFileAppender.TOP_OF_HOUR : + this.set(Calendar.MINUTE, 0); + this.set(Calendar.SECOND, 0); + this.set(Calendar.MILLISECOND, 0); + this.add(Calendar.HOUR_OF_DAY, 1); + break; + case EnhancedDailyRollingFileAppender.HALF_DAY : + this.set(Calendar.MINUTE, 0); + this.set(Calendar.SECOND, 0); + this.set(Calendar.MILLISECOND, 0); + int hour = get(Calendar.HOUR_OF_DAY); + if (hour < 12) + { + this.set(Calendar.HOUR_OF_DAY, 12); + } + else + { + this.set(Calendar.HOUR_OF_DAY, 0); + this.add(Calendar.DAY_OF_MONTH, 1); + } + break; + case EnhancedDailyRollingFileAppender.TOP_OF_DAY : + this.set(Calendar.HOUR_OF_DAY, 0); + this.set(Calendar.MINUTE, 0); + this.set(Calendar.SECOND, 0); + this.set(Calendar.MILLISECOND, 0); + this.add(Calendar.DATE, 1); + break; + case EnhancedDailyRollingFileAppender.TOP_OF_WEEK : + this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek()); + this.set(Calendar.HOUR_OF_DAY, 0); + this.set(Calendar.SECOND, 0); + this.set(Calendar.MILLISECOND, 0); + this.add(Calendar.WEEK_OF_YEAR, 1); + break; + case EnhancedDailyRollingFileAppender.TOP_OF_MONTH : + this.set(Calendar.DATE, 1); + this.set(Calendar.HOUR_OF_DAY, 0); + this.set(Calendar.SECOND, 0); + this.set(Calendar.MILLISECOND, 0); + this.add(Calendar.MONTH, 1); + break; + default : + throw new IllegalStateException("Unknown periodicity type."); + } + return getTime(); + } +} Property changes on: trunk/openutils-log4j/src/main/java/it/openutils/log4j/EnhancedDailyRollingFileAppender.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Added: trunk/openutils-log4j/src/site/apt/fileppenders.apt =================================================================== --- trunk/openutils-log4j/src/site/apt/fileppenders.apt (rev 0) +++ trunk/openutils-log4j/src/site/apt/fileppenders.apt 2008-01-26 13:53:20 UTC (rev 544) @@ -0,0 +1,28 @@ + -------------------------- + O p e n u t i l s + -------------------------- + Fabrizio Giustina + -------------------------- + +EnhancedDailyRollingFileAppender + + The standard org.apache.log4j.DailyRollingFileAppender lets you only add a suffix to the original log file name, +renaming for example <<<error.log>>> to <<<error.log.2008-02-23>>>. + + This appender also allow moving archived file to a different directory, by setting the <<<ArchiveDirectory>>> property + (default is <<<archive>>>) + + + ++----------------------------------------------+ + <appender name="log" class="it.openutils.log4j.EnhancedDailyRollingFileAppender"> + <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" /> + <param name="ArchiveDirectory" value="archive" /> + <param name="File" value="/data/logs/error.log" /> + <param name="Threshold" value="INFO" /> + <param name="Append" value="true" /> + <layout class="org.apache.log4j.PatternLayout"> + <param name="ConversionPattern" value="%d{dd.MM.yyyy HH:mm:ss} %m%n" /> + </layout> + </appender> ++----------------------------------------------+ \ No newline at end of file Property changes on: trunk/openutils-log4j/src/site/apt/fileppenders.apt ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Modified: trunk/openutils-log4j/src/site/apt/index.apt =================================================================== --- trunk/openutils-log4j/src/site/apt/index.apt 2008-01-22 21:17:56 UTC (rev 543) +++ trunk/openutils-log4j/src/site/apt/index.apt 2008-01-26 13:53:20 UTC (rev 544) @@ -15,6 +15,8 @@ * {{{servlet.html}a ready to use configuration servlet that let you change logging levels on the fly}} + * {{{fileappenders.html} an extended version of the standard DailyRollingFileAppender}} + [] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fg...@us...> - 2008-03-11 15:24:18
|
Revision: 731 http://openutils.svn.sourceforge.net/openutils/?rev=731&view=rev Author: fgiust Date: 2008-03-11 08:24:20 -0700 (Tue, 11 Mar 2008) Log Message: ----------- Make it.openutils.log4j.AlternateSMTPAppender working properly also when no timeout Modified Paths: -------------- trunk/openutils-log4j/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java trunk/openutils-log4j/src/site/changes/changes.xml Modified: trunk/openutils-log4j/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java =================================================================== --- trunk/openutils-log4j/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java 2008-03-06 09:27:01 UTC (rev 730) +++ trunk/openutils-log4j/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java 2008-03-11 15:24:20 UTC (rev 731) @@ -59,7 +59,7 @@ * <li>it will send a mail for every single message (bufferSize is not supported), but it will aggregate any identical * log event received during the timeout. Identical events are log with same message and same stack trace</li> * </ul> - * + * * <pre> * <appender name="mail" class="it.openutils.log4j.AlternateSMTPAppender"> * <param name="Threshold" value="ERROR" /> @@ -80,7 +80,7 @@ * </layout> * </appender> * </pre> - * + * * @author Fabrizio Giustina * @version $Id: $ */ @@ -211,39 +211,48 @@ LoggingEventAggregator leg = new LoggingEventAggregator(event); - events.put(leg, leg); - if (evaluator.isTriggeringEvent(event)) { if (timeout == 0) { // send immediately - sendBuffer(events.values()); + synchronized (events) + { + Collection<LoggingEventAggregator> le = new ArrayList<LoggingEventAggregator>(); + le.add(leg); + sendBuffer(le); + } return; } - if (timerTask == null) + else { + events.put(leg, leg); - timerTask = new TimerTask() + if (timerTask == null) + { - @Override - public void run() + timerTask = new TimerTask() { - Collection<LoggingEventAggregator> le; - synchronized (events) + + @Override + public void run() { - le = new ArrayList<LoggingEventAggregator>(events.values()); - events.clear(); - timerTask = null; + Collection<LoggingEventAggregator> le; + synchronized (events) + { + le = new ArrayList<LoggingEventAggregator>(events.values()); + events.clear(); + timerTask = null; + } + + sendBuffer(le); } + }; - sendBuffer(le); - } - }; + this.timer.schedule(this.timerTask, this.timeout * 1000L); - this.timer.schedule(this.timerTask, this.timeout * 1000L); - + } } } } Modified: trunk/openutils-log4j/src/site/changes/changes.xml =================================================================== --- trunk/openutils-log4j/src/site/changes/changes.xml 2008-03-06 09:27:01 UTC (rev 730) +++ trunk/openutils-log4j/src/site/changes/changes.xml 2008-03-11 15:24:20 UTC (rev 731) @@ -8,9 +8,13 @@ <author email="fgiust(at)users.sourceforge.net">Fabrizio Giustina</author> </properties> <body> + <release version="2.0.1" date="2008-03-11" description="2.0.1"> + <action type="add" dev="fgiust"> Make it.openutils.log4j.AlternateSMTPAppender working properly also when no timeout + is set (withot message aggregation).</action> + <action type="update" dev="fgiust">commons-lang dependency added</action> + </release> <release version="2.0" date="2008-02-20" description="2.0.0"> - <action type="add" dev="fgiust"> - new it.openutils.log4j.AlternateSMTPAppender that aggregates similar log messages. + <action type="add" dev="fgiust"> new it.openutils.log4j.AlternateSMTPAppender that aggregates similar log messages. </action> <action type="update" dev="fgiust">commons-lang dependency added</action> </release> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |