DailyRollingFileAppende每天(yyyy-MM-dd)生成一个日志文件,但是当天的文件没有日期后缀。试着重写了一下他的方法。
主要注意这个方法public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException
还有这个void rollOver() throws IOException
【注】有个问题没有解决,当服务器将时间调向过去,日志不会写到那天的日志文件里,而是会写到最新的日志文件里;系统时间调向将来,没有问题。
/**
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software
* License version 1.1, a copy of which has been included with this
* distribution in the file. */
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .;
import .;
import .;
/***
DailyRollingFileAppender extends {@link FileAppender} so that the
underlying file is rolled over at a user chosen frequency.
<p>The rolling schedule is specified by the <b>DatePattern</b>
option. This pattern should follow the {@link SimpleDateFormat}
conventions. In particular, you <em>must</em> escape literal text
within a pair of single quotes. A formatted version of the date
pattern is used as the suffix for the rolled file name.
<p>For example, if the <b>File</b> option is set to
<code>/foo/</code> and the <b>DatePattern</b> set to
<code>'.'yyyy-MM-dd</code>, on 2001-02-16 at midnight, the logging
file <code>/foo/</code> will be copied to
<code>/foo/.2001-02-16</code> and logging for 2001-02-17
will continue in <code>/foo/</code> until it rolls over
the next day.
<p>Is is possible to specify monthly, weekly, half-daily, daily,
hourly, or minutely rollover schedules.
<p><table border="1" cellpadding="2">
<tr>
<th>DatePattern</th>
<th>Rollover schedule</th>
<th>Example</th>
<tr>
<td><code>'.'yyyy-MM</code>
<td>Rollover at the beginning of each month</td>
<td>At midnight of May 31st, 2002 <code>/foo/</code> will be
copied to <code>/foo/.2002-05</code>. Logging for the month
of June will be output to <code>/foo/</code> until it is
also rolled over the next month.
<tr>
<td><code>'.'yyyy-ww</code>
<td>Rollover at the first day of each week. The first day of the
week depends on the locale.</td>
<td>Assuming the first day of the week is Sunday, on Saturday
midnight, June 9th 2002, the file <i>/foo/</i> will be
copied to <i>/foo/.2002-23</i>. Logging for the 24th week
of 2002 will be output to <code>/foo/</code> until it is
rolled over the next week.
<tr>
<td><code>'.'yyyy-MM-dd</code>
<td>Rollover at midnight each day.</td>
<td>At midnight, on March 8th, 2002, <code>/foo/</code> will
be copied to <code>/foo/.2002-03-08</code>. Logging for the
9th day of March will be output to <code>/foo/</code> until
it is rolled over the next day.
<tr>
<td><code>'.'yyyy-MM-dd-a</code>
<td>Rollover at midnight and midday of each day.</td>
<td>At noon, on March 9th, 2002, <code>/foo/</code> will be
copied to <code>/foo/.2002-03-09-AM</code>. Logging for the
afternoon of the 9th will be output to <code>/foo/</code>
until it is rolled over at midnight.
<tr>
<td><code>'.'yyyy-MM-dd-HH</code>
<td>Rollover at the top of every hour.</td>
<td>At approximately 11:00.000 o'clock on March 9th, 2002,
<code>/foo/</code> will be copied to
<code>/foo/.2002-03-09-10</code>. Logging for the 11th hour
of the 9th of March will be output to <code>/foo/</code>
until it is rolled over at the beginning of the next hour.
<tr>
<td><code>'.'yyyy-MM-dd-HH-mm</code>
<td>Rollover at the beginning of every minute.</td>
<td>At approximately 11:23,000, on March 9th, 2001,
<code>/foo/</code> will be copied to
<code>/foo/.2001-03-09-10-22</code>. Logging for the minute
of 11:23 (9th of March) will be output to
<code>/foo/</code> until it is rolled over the next minute.
</table>
<p>Do not use the colon ":" character in anywhere in the
<b>DatePattern</b> option. The text before the colon is interpeted
as the protocol specificaion of a URL which is probably not what
you want.
@author Eirik Lygre
@author Ceki Gülcü */
public class DailyRollingFileAppender 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;
/***
The next time we estimate a rollover should occur. */
private long nextCheck = () - 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 = ("GMT");
/***
The default constructor does nothing. */
public DailyRollingFileAppender() {
}
/***
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 DailyRollingFileAppender (Layout layout, String filename,
String datePattern) throws IOException {
super(layout, filename, true);
= datePattern;
activateOptions();
}
/***
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() {
();
if(datePattern != null && fileName != null) {
(());
sdf = new SimpleDateFormat(datePattern);
int type = computeCheckPeriod();
printPeriodicity(type);
(type);
File file = new File(fileName);
// String name0=(new Date());
// String name1=((new Date()));
// if((name0)||(name1)){
scheduledFilename = fileName;
// }else{
// scheduledFilename = fileName+(new Date(()));
// }
} else {
("Either File or DatePattern options are not set for appender ["
+name+"].");
}
}
void printPeriodicity(int type) {
switch(type) {
case TOP_OF_MINUTE:
("Appender ["+name+"] to be rolled every minute.");
break;
case TOP_OF_HOUR:
("Appender ["+name
+"] to be rolled on top of every hour.");
break;
case HALF_DAY:
("Appender ["+name
+"] to be rolled at midday and midnight.");
break;
case TOP_OF_DAY:
("Appender ["+name
+"] to be rolled at midnight.");
break;
case TOP_OF_WEEK:
("Appender ["+name
+"] to be rolled at start of week.");
break;
case TOP_OF_MONTH:
("Appender ["+name
+"] to be rolled at start of every month.");
break;
default:
("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, );
// 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);
(gmtTimeZone); // do all date formatting in GMT
String r0 = (epoch);
(i);
Date next = new Date((epoch));
String r1 = (next);
//("Type = "+i+", r0 = "+r0+", r1 = "+r1);
if(r0 != null && r1 != null && !(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) {
("Missing DatePattern option in rollOver().");
return;
}
String datedFilename = fileName;
String str=(now);
=(0, ("."))+str;
// 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 ((datedFilename)) {
return;
}
// close current file, and rename it to datedFilename
();
File target = new File(scheduledFilename);
if (()) {
();
String s=null;
}
//注意这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// File file = new File(fileName);
// boolean result = (target);
// if(result) {
// (fileName +" -> "+ scheduledFilename);
// } else {
// ("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
// }
try {
// This will also close the file. This is OK since multiple
// close operations are safe.
(fileName, false, , );
}
catch(IOException e) {
("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 = ();
if (n >= nextCheck) {
(n);
nextCheck = (now);
try {
rollOver();
}
catch(IOException ioe) {
("rollOver() failed.", ioe);
}
}
(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 = DailyRollingFileAppender.TOP_OF_TROUBLE;
RollingCalendar() {
super();
}
RollingCalendar(TimeZone tz, Locale locale) {
super(tz, locale);
}
void setType(int type) {
= type;
}
public long getNextCheckMillis(Date now) {
return getNextCheckDate(now).getTime();
}
public Date getNextCheckDate(Date now) {
(now);
switch(type) {
case DailyRollingFileAppender.TOP_OF_MINUTE:
(, 0);
(, 0);
(, 1);
break;
case DailyRollingFileAppender.TOP_OF_HOUR:
(, 0);
(, 0);
(, 0);
(Calendar.HOUR_OF_DAY, 1);
break;
case DailyRollingFileAppender.HALF_DAY:
(, 0);
(, 0);
(, 0);
int hour = get(Calendar.HOUR_OF_DAY);
if(hour < 12) {
(Calendar.HOUR_OF_DAY, 12);
} else {
(Calendar.HOUR_OF_DAY, 0);
(Calendar.DAY_OF_MONTH, 1);
}
break;
case DailyRollingFileAppender.TOP_OF_DAY:
(Calendar.HOUR_OF_DAY, 0);
(, 0);
(, 0);
(, 0);
(, 1);
break;
case DailyRollingFileAppender.TOP_OF_WEEK:
(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
(Calendar.HOUR_OF_DAY, 0);
(, 0);
(, 0);
(Calendar.WEEK_OF_YEAR, 1);
break;
case DailyRollingFileAppender.TOP_OF_MONTH:
(, 1);
(Calendar.HOUR_OF_DAY, 0);
(, 0);
(, 0);
(, 1);
break;
default:
throw new IllegalStateException("Unknown periodicity type.");
}
return getTime();
}
}
/**
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software
* License version 1.1, a copy of which has been included with this
* distribution in the file. */
package ;
import ;
import ;
import ;
import ;
import ;
import .;
import .;
import .;
import .;
import .;
import .;
import .;
// Contibutors: Jens Uwe Pipka <@>
// Ben Sandee
/***
* FileAppender appends log events to a file.
*
* <p>Support for <code></code> and console appending
* has been deprecated and then removed. See the replacement
* solutions: {@link WriterAppender} and {@link ConsoleAppender}.
*
* @author Ceki Gülcü
* */
public class FileAppender extends WriterAppender {
/*** Append to or truncate the file? The default value for this
variable is <code>true</code>, meaning that by default a
<code>FileAppender</code> will append to an existing file and
not truncate it.
<p>This option is meaningful only if the FileAppender opens the
file.
*/
protected boolean fileAppend = true;
/***
The name of the log file. */
protected String fileName = null;
/***
Do we do bufferedIO? */
protected boolean bufferedIO = false;
/***
How big should the IO buffer be? Default is 8K. */
protected int bufferSize = 8*1024;
protected static simpleDateFormat = new ("yyyy-MM-dd");
/***
The default constructor does not do anything.
*/
public
FileAppender() {
}
/***
Instantiate a <code>FileAppender</code> and open the file
designated by <code>filename</code>. The opened filename will
become the output destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file designated by
<code>filename</code> will be truncated before being opened.
<p>If the <code>bufferedIO</code> parameter is <code>true</code>,
then buffered IO will be used to write to the output file.
*/
public
FileAppender(Layout layout, String filename, boolean append, boolean bufferedIO,
int bufferSize) throws IOException {
= layout;
filename=filename+"."+(new Date());
(filename, append, bufferedIO, bufferSize);
}
/***
Instantiate a FileAppender and open the file designated by
<code>filename</code>. The opened filename will become the output
destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file designated by
<code>filename</code> will be truncated before being opened.
*/
public
FileAppender(Layout layout, String filename, boolean append)
throws IOException {
= layout;
(filename, append, false, bufferSize);
}
/***
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
FileAppender(Layout layout, String filename) throws IOException {
this(layout, filename, true);
}
/***
The <b>File</b> property takes a string value which should be the
name of the file to append to.
<p><font color="#DD0044"><b>Note that the special values
"" or "" are no longer honored.</b></font>
<p>Note: Actual opening of the file is made when {@link
#activateOptions} is called, not when the options are set. */
public void setFile(String file) {
// Trim spaces from both ends. The users probably does not want
// trailing spaces in file names.
String val = ();
fileName = val;
}
/***
Returns the value of the <b>Append</b> option.
*/
public
boolean getAppend() {
return fileAppend;
}
/*** Returns the value of the <b>File</b> option. */
public
String getFile() {
return fileName;
}
/***
If the value of <b>File</b> is not <code>null</code>, then {@link
#setFile} is called with the values of <b>File</b> and
<b>Append</b> properties.
@since 0.8.1 */
public
void activateOptions() {
if(fileName != null) {
try {
setFile(fileName, fileAppend, bufferedIO, bufferSize);
}
catch( e) {
("setFile("+fileName+","+fileAppend+") call failed.",
e, ErrorCode.FILE_OPEN_FAILURE);
}
} else {
//("File option not set for appender ["+name+"].");
("File option not set for appender ["+name+"].");
("Are you using FileAppender instead of ConsoleAppender?");
}
}
/***
Closes the previously opened file.
*/
protected
void closeFile() {
if( != null) {
try {
();
}
catch( e) {
// Exceptionally, it does not make sense to delegate to an
// ErrorHandler. Since a closed appender is basically dead.
("Could not close " + qw, e);
}
}
}
/***
Get the value of the <b>BufferedIO</b> option.
<p>BufferedIO will significatnly increase performance on heavily
loaded systems.
*/
public
boolean getBufferedIO() {
return ;
}
/***
Get the size of the IO buffer.
*/
public
int getBufferSize() {
return ;
}
/***
The <b>Append</b> option takes a boolean value. It is set to
<code>true</code> by default. If true, then <code>File</code>
will be opened in append mode by {@link #setFile setFile} (see
above). Otherwise, {@link #setFile setFile} will open
<code>File</code> in truncate mode.
<p>Note: Actual opening of the file is made when {@link
#activateOptions} is called, not when the options are set.
*/
public
void setAppend(boolean flag) {
fileAppend = flag;
}
/***
The <b>BufferedIO</b> option takes a boolean value. It is set to
<code>false</code> by default. If true, then <code>File</code>
will be opened and the resulting {@link } wrapped
around a {@link BufferedWriter}.
BufferedIO will significatnly increase performance on heavily
loaded systems.
*/
public
void setBufferedIO(boolean bufferedIO) {
= bufferedIO;
if(bufferedIO) {
immediateFlush = false;
}
}
/***
Set the size of the IO buffer.
*/
public
void setBufferSize(int bufferSize) {
= bufferSize;
}
/***
<p>Sets and <i>opens</i> the file where the log output will
go. The specified file must be writable.
<p>If there was already an opened file, then the previous file
is closed first.
<p><b>Do not use this method directly. To configure a FileAppender
or one of its subclasses, set its properties one by one and then
call activateOptions.</b>
@param fileName The path to the log file.
@param append If true will append to fileName. Otherwise will
truncate fileName. */
public
synchronized
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
throws IOException {
("setFile called: "+fileName+", "+append);
// It does not make sense to have immediate flush and bufferedIO.
if(bufferedIO) {
setImmediateFlush(false);
}
//注意这里。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
reset();
String suffix=(new Date());
if((".")){
String str=(0, ("."));
if((".")){
=(0, ("."))+"."+suffix;
fileName=(0, ("."))+"."+suffix;
}
else{
=str+"."+suffix;
fileName=str+"."+suffix;
}
}else{
=fileName+"."+suffix;
fileName=fileName+"."+suffix;
}
Writer fw = createWriter(new FileOutputStream(fileName, append));
if(bufferedIO) {
fw = new BufferedWriter(fw, bufferSize);
}
(fw);
= fileName;
= append;
= bufferedIO;
= bufferSize;
writeHeader();
("setFile ended");
}
/***
Sets the quiet writer being used.
This method is overriden by {@link RollingFileAppender}.
*/
protected
void setQWForFiles(Writer writer) {
= new QuietWriter(writer, errorHandler);
}
/***
Close any previously opened file and call the parent's
<code>reset</code>. */
protected
void reset() {
closeFile();
= null;
();
}
}