In most appender of log4j, there are maxbackupindex attributes, but this dailyrollingfileappender does not, that is, it rolls a file every day, but there is no way to control the total number of files. This is definitely a "fire point" in the system, and the following is the beginning of the transformation:
One. To study the appender structure of the whole log4j:
Extending a module of a framework is not always a straightforward inheritance of a class, and it is possible to fall into some traps without further in-depth research. (such as extending the log4j logger class, inheriting it directly does not get any benefit, specifically explaining the reference to the official document.) Fortunately log4j has a good support for the expansion of Level,appender,layerout.
Then it is to look at the log4j configuration file. A configuration file can directly configure the extended Appender property, which saves us a bunch of definitions, parsing, and processing processes
Java code <span style= "COLOR: #ff0000" ># give its own class A corresponding name </SPAN> log4j.appender.appendername=fully.qualified. Name.of.appender. class <span style= "COLOR: #ff0000" > #还可以给自己的类property设置值, which means that extended Maxbackupindex properties can be configured </SPAN> Log4j.appender.appendername.option1=value1 ... Log4j.appender.appendername.optionn=valuen
# take a corresponding name Log4j.appender.appendername=fully.qualified.name.of.appender.class #还可以给自己的类property设置值 for your class
, This means that the extended Maxbackupindex property can be configured with
log4j.appender.appendername.option1=value1
...
Log4j.appender.appendername.optionn=valuen
Two. After roughly, you can start to see the source of Dailyrollingfileappender.
Look directly at attribute and method structure
Can be roughly guessed that this class did the following things: Inherit the root class Appender, support Datepattern resolution and Datepattern settings for the rolling conditions of the assembly filename, implementation "Listening" method, to the point of switching logfile ... Most of the work has been done for us:
The only thing that needs to be changed now is the "Toggle File" method, which deletes the oldest n log while switching to a new file.
Java code/** Rollover the current file to a new file. */voidRollover ()throwsIOException {/* 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 the '//within of the ' current bounds. Rollover'll occur once the//next interval is reached.if(Scheduledfilename.equals (Datedfilename)) { return; }//close current file, and rename it to Datedfilename This. CloseFile (); File target =NewFile (Scheduledfilename);if(Target.exists ()) {Target.delete (); } File File =NewFile (FileName);Booleanresult = File.renameto (target);if(Result) {Loglog.debug (fileName + "->" + scheduledfilename); }Else{Loglog.error ("Failed to rename [" +filename+ "] to [" +scheduledfilename+ "]."); }Try{//This'll 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; }
/** rollover The current file to a new file. */void Rollover () throws IOException {/* Compute filename, but only if Datepattern is specified/if (Datepa
Ttern = = 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 the '//within of the ' current bounds.
Rollover'll occur once the//next interval is reached.
if (Scheduledfilename.equals (Datedfilename)) {return;
}//close current file, and rename it to Datedfilename This.closefile ();
File target = new file (scheduledfilename);
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 [" +schedulEdfilename+ "]."); try {//This'll 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; }
See here to find the problem, because the Datepattern format can be configured, then the resulting scrolling file name is also different, there is no law to follow.
For example, ". Yyyy-ww", which is scrolled by the week, will cause an error when the configuration is changed to ". Yyyy-mm" to scroll through the month, and deleting old files through file name matching.
In addition, the log file switch is not timed polling but event-promoting mechanism, only when the write operation will be to determine whether the need to scroll files. The write operation, when executed across a rolling cycle, creates a vacancy in the file name and does not guarantee continuity.
Perhaps that is why log4j itself does not limit the number of files in this appender.
Three. Compromise it.
The framework is always as powerful as possible, but it is always the simplest of features to use. In the IDC environment is usually not allowed to scroll log log in time, mainly to prevent logging files to support the hard drive to become a point of ignition. Here, consider enabling time scrolling, primarily performance log statistics scripts require log files to be stored by day, and only need to be backed up to date.
Then my need is simple: simplify the function.
Imitation Dailyrollingfileappender implementation 1. Only the day-scrolling, 2-formatted Datepattern, 3. The maximum number of backup files is n appender. (The number of backups can be considered flexible, but there must be a parameter check to prevent in case.) )
Limit the Datepattern, on the one hand can prevent the mismatch, make into a monthly rolling must die; On the other hand it is also easy to handle maxbackupindex delete history files. More, now that you know that scrolling by the day, the check method can certainly be simplified:
The final modified version of the day scrolling Appender is as follows:
Java codePackageCXXXXXXXJ;ImportJava.io.File;ImportJava.io.IOException;ImportJava.text.SimpleDateFormat;ImportJava.util.ArrayList;ImportJava.util.Calendar;ImportJava.util.Date;ImportJava.util.List;ImportOrg.apache.log4j.FileAppender;ImportOrg.apache.log4j.Layout;ImportOrg.apache.log4j.helpers.LogLog;ImportOrg.apache.log4j.spi.LoggingEvent; /** * Extended One-day Appender class * does not support Datepattern settings temporarily, but can be configured Maxbackupindex * @author weisong * * * PublicclassDayrollingfileappenderextendsFileappender {/** not allowed to rewrite Datepattern * *Private FinalString Datepattern = "'. ' Yyyy-mm-dd "; /** maximum number of file growth * *PrivateintMaxbackupindex = 2; /** "filename + last Last updated" * *PrivateString Scheduledfilename; /** the next time we estimate a rollover should occur. */PrivateLongNextcheck = System.currenttimemillis ()-1; Date now =NewDate (); SimpleDateFormat SDF; /** the default constructor does nothing. */ PublicDayrollingfileappender () {}/** modified constructor * * PublicDayrollingfileappender (Layout Layout, String filename,intMaxbackupindex)throwsIOException {Super(Layout, filename,true); This. Maxbackupindex = Maxbackupindex; Activateoptions (); /** * To initialize the Appender object when it is called once/ PublicvoidActivateoptions () {Super. Activateoptions ();if(FileName!=NULL) {//perf.log now.settime (System.currenttimemillis ()); SDF =NewSimpleDateFormat (Datepattern); File File =NewFile (FileName); Gets the filename of the last update time Scheduledfilename = Filename+sdf.format (NewDate (File.lastmodified ())); }Else{Loglog.error ("File is not set for Appender [" +name+]. "); }if(maxbackupindex<=0) {loglog.error ("Maxbackupindex Reset to default value[2],orignal value is:" + maxbackupindex); maxbackupindex=2; /** the function of scrolling file: 1. Compare the timestamp of the file name with, determine whether to update the 2.if need to update, the current file rename to the filename + date, start writing again File 3. For configured Maxbackupindex, delete expired files.voidRollover ()throwsIOException {String Datedfilename = fileName + Sdf.format (now); If you last wrote the same date as the current date, you do not need to change the fileif(Scheduledfilename.equals (Datedfilename)) { return; }//close current file, and rename it to Datedfilename This. CloseFile (); File target =NewFile (Scheduledfilename);if(Target.exists ()) {Target.delete (); } File File =NewFile (FileName);Booleanresult = File.renameto (target);if(Result) {Loglog.debug (fileName + "->" + scheduledfilename); }Else{Loglog.error ("Failed to rename [" + FileName +] to ["+ Scheduledfilename +"]. " ); }//Delete expired fileif(Maxbackupindex > 0) {File folder =NewFile (File.getparent ()); list<string> maxbackupindexdates = Getmaxbackupindexdates (); for(File ff:folder.listFiles ()) {//traverse the directory, delete the date that is not in the backup rangeif (Ff.getname (). StartsWith (File.getname ()) && !ff.getname (). Equals (File.getname ())) { //gets the file name band's date time stamp &