packagecom.ctid.dnc.system.fileappender;/**
* @ProductName: IntelliJ IDEA
* @ProjectName:
* @Description:
* @User: Tangerine
* @Email: yj_tangerine@163.com | yj_tangerine@sina.com
* @Date: 2021/11/25 16:59 星期四
* @version: V1.0.0
*/importorg.apache.log4j.FileAppender;importorg.apache.log4j.Layout;importorg.apache.log4j.helpers.CountingQuietWriter;importorg.apache.log4j.helpers.LogLog;importorg.apache.log4j.helpers.OptionConverter;importorg.apache.log4j.spi.LoggingEvent;importjava.io.File;importjava.io.IOException;importjava.io.Writer;importjava.text.SimpleDateFormat;importjava.util.Date;importjava.util.Locale;importjava.util.TimeZone;publicclassLog4JDateAndSizeSplitextendsFileAppender{// The code assumes that the following constants are in a increasing// sequence.staticfinalint TOP_OF_TROUBLE =-1;staticfinalint TOP_OF_MINUTE =0;staticfinalint TOP_OF_HOUR =1;staticfinalint HALF_DAY =2;staticfinalint TOP_OF_DAY =3;staticfinalint TOP_OF_WEEK =4;staticfinalint TOP_OF_MONTH =5;/**
* The default maximum file size is 10MB.
*/protectedlong maxFileSize =10*1024*1024;/**
* There is one backup file by default.
*/protectedint maxBackupIndex =1;/**
* meaning daily rollover.
*/privateString datePattern ="'.'yyyy-MM-dd";/**
* "scheduledFilename" at the beginning of the next hour.
*/privateString scheduledFilename;/**
* The next time we estimate a rollover should occur.
*/privatelong nextCheck =System.currentTimeMillis()-1;Date now =newDate();SimpleDateFormat sdf;RollingCalendar rc =newRollingCalendar();int checkPeriod = TOP_OF_TROUBLE;// The gmtTimeZone is used only in computeCheckPeriod() method.staticfinalTimeZone gmtTimeZone =TimeZone.getTimeZone("GMT");{super.fileName ="/xxx/xxxx/xxxx/"+newSimpleDateFormat("yyyyMMdd").format(newDate())+".log";//System.out.println(super.fileName);}publicLog4JDateAndSizeSplit(){}publicLog4JDateAndSizeSplit(Layout layout,String filename,String datePattern)throwsIOException{super(layout, filename,true);this.datePattern = datePattern;activateOptions();}publiclonggetMaximumFileSize(){return maxFileSize;}publicvoidsetMaximumFileSize(long maxFileSize){this.maxFileSize = maxFileSize;}publicvoidsetMaxFileSize(String value){maxFileSize =OptionConverter.toFileSize(value, maxFileSize +1);}publicintgetMaxBackupIndex(){return maxBackupIndex;}publicvoidsetMaxBackupIndex(int maxBackups){this.maxBackupIndex = maxBackups;}publicvoidsetDatePattern(String pattern){datePattern = pattern;}publicStringgetDatePattern(){return datePattern;}@OverridepublicvoidactivateOptions(){super.activateOptions();if(datePattern !=null&& fileName !=null){
now.setTime(System.currentTimeMillis());
sdf =newSimpleDateFormat(datePattern);int type =computeCheckPeriod();printPeriodicity(type);
rc.setType(type);File file =newFile(fileName);//scheduledFilename = fileName + sdf.format(new Date(file.lastModified()));
scheduledFilename = fileName.substring(0, fileName.lastIndexOf("/"))+"/"+ sdf.format(newDate(file.lastModified()));}else{LogLog.error("Either File or DatePattern options are not set for appender ["+ name +"].");}}voidprintPeriodicity(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).intcomputeCheckPeriod(){RollingCalendar rollingCalendar =newRollingCalendar(gmtTimeZone,Locale.ENGLISH);// set sate to 1970-01-01 00:00:00 GMTDate epoch =newDate(0);if(datePattern !=null){for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++){SimpleDateFormat simpleDateFormat =newSimpleDateFormat(datePattern);
simpleDateFormat.setTimeZone(gmtTimeZone);// do all date// formatting in GMTString r0 = simpleDateFormat.format(epoch);
rollingCalendar.setType(i);Date next =newDate(rollingCalendar.getNextCheckMillis(epoch));String r1 = simpleDateFormat.format(next);// System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);if(r0 !=null&& r1 !=null&&!r0.equals(r1)){return i;}}}return TOP_OF_TROUBLE;// Deliberately head for trouble...}/**这边我们是递增文件,所以maxBackupIndex是-1 所以不会删除文件,让windows不高兴*/publicvoidsizeRollOver(){File target;File file;LogLog.debug("rolling over count="+((CountingQuietWriter) qw).getCount());LogLog.debug("maxBackupIndex="+ maxBackupIndex);String datedFilename = fileName.substring(0, fileName.lastIndexOf("/"))+"/"+newSimpleDateFormat("yyyyMMdd").format(now)+"_";if(maxBackupIndex >0){// Delete the oldest file, to keep Windows happy.
file =newFile(datedFilename +'.'+ maxBackupIndex);if(file.exists())
file.delete();for(int i = maxBackupIndex -1; i >=1; i--){
file =newFile(datedFilename + i +".log");if(file.exists()){
target =newFile(datedFilename +(i +1)+".log");LogLog.debug("Renaming file "+ file +" to "+ target);
file.renameTo(target);}}// Rename fileName to datedFilename.1
target =newFile(datedFilename +"."+1);this.closeFile();// keep windows happy.
file =newFile(fileName);LogLog.debug("Renaming file "+ file +" to "+ target);
file.renameTo(target);}elseif(maxBackupIndex <0){// infinite number of files// find the max backup indexfor(int i =1; i <Integer.MAX_VALUE; i++){
target =newFile(datedFilename + i +".log");if(!target.exists()){// Rename fileName to datedFilename.ithis.closeFile();
file =newFile(fileName);
file.renameTo(target);LogLog.debug("Renaming file "+ file +" to "+ target);break;}}}try{// This will also close the file. This is OK since multiple// close operations are safe.this.setFile(fileName,false, bufferedIO, bufferSize);}catch(IOException e){LogLog.error("setFile("+ fileName +", false) call failed.", e);}
scheduledFilename = datedFilename;}@OverridepublicsynchronizedvoidsetFile(String fileName,boolean append,boolean bufferedIO,int bufferSize)throwsIOException{super.setFile(fileName, append,this.bufferedIO,this.bufferSize);if(append){File f =newFile(fileName);((CountingQuietWriter) qw).setCount(f.length());}}@OverrideprotectedvoidsetQWForFiles(Writer writer){this.qw =newCountingQuietWriter(writer, errorHandler);}/**
* Rollover the current file to a new file.
*/voidtimeRollOver()throwsIOException{/* Compute filename, but only if datePattern is specified */if(datePattern ==null){
errorHandler.error("Missing DatePattern option in rollOver().");return;}String datedFilename = fileName.substring(0, fileName.lastIndexOf("/"))+"/"+newSimpleDateFormat("yyyyMMdd").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 datedFilenamethis.closeFile();File target =null;//xxxx/20211125_3.logfor(int i =1; i <Integer.MAX_VALUE; i++){
target =newFile(scheduledFilename + i +".log");if(!target.exists())break;}File file =newFile(fileName);boolean result = file.renameTo(target);if(result){LogLog.debug(fileName +" -> "+ scheduledFilename);
fileName = fileName.substring(0, fileName.lastIndexOf("/")+1)+newSimpleDateFormat("yyyyMMdd").format(newDate())+".log";}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.super.setFile(fileName,false,this.bufferedIO,this.bufferSize);}catch(IOException e){
errorHandler.error("setFile("+ fileName +", false) call failed.");}
scheduledFilename = datedFilename;}@OverrideprotectedvoidsubAppend(LoggingEvent event){long n =System.currentTimeMillis();if(n >= nextCheck){//如果时间大于了,进去
now.setTime(n);
nextCheck = rc.getNextCheckMillis(now);try{timeRollOver();}catch(IOException ioe){LogLog.error("rollOver() failed.", ioe);}}elseif((fileName !=null)&&((CountingQuietWriter) qw).getCount()>= maxFileSize){//如果文件大小大于了,进去sizeRollOver();}super.subAppend(event);}}