LOG4J实现日切或者时切

LOG4J 存在一个问题,一段时间内没有打印日志,LOG4J日志归档会空缺一些日志文件。

如果有监控系统对日志文件进行监控,可能就会导致误判。

如果在程序中定时向LOG4J中打印日志或者空格(打一个空格也会存在一个换行)也可以,但是会破坏日志的完整性,监控程序可能会解析出错等。

经过研究,提供一种方法,修改LOG4J的源码,保证无日志打印,日志文件也会定时归档。

1、重写 DailyRollingFileAppende 类。


package com.pouyang.log4j;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

public class UmpDailyRollingFileAppender extends FileAppender
{
  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;
  private String datePattern = "'.'yyyy-MM-dd";
  private String scheduledFilename;
  private long nextCheck = System.currentTimeMillis() - 1L;
  
  private String categoryName = "MPSP";

  Date now = new Date();
  SimpleDateFormat sdf;
  RollingCalendar rc = new RollingCalendar();
  Timer timer;
  org.slf4j.Logger _log ;
  
  int checkPeriod = -1;

  static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");

  public UmpDailyRollingFileAppender()
  {
	  System.out.println("UmpDailyRollingFileAppender()"+this);
  }

  public UmpDailyRollingFileAppender(Layout layout, String filename, String datePattern)
    throws IOException
  {
    super(layout, filename, true);
    this.datePattern = datePattern;
    activateOptions();
    System.out.println("UmpDailyRollingFileAppender()"+this);
  }

  public void setDatePattern(String pattern)
  {
    this.datePattern = pattern;
  }

  public String getDatePattern()
  {
    return this.datePattern;
  }

  public void activateOptions() {
    super.activateOptions();
    if ((this.datePattern != null) && (this.fileName != null)) {
      this.now.setTime(System.currentTimeMillis());
      this.sdf = new SimpleDateFormat(this.datePattern);
      int type = computeCheckPeriod();
      printPeriodicity(type);
      this.rc.setType(type);
      File file = new File(this.fileName);
      this.scheduledFilename = 
        (this.fileName + 
        this.sdf.format(new Date(file.lastModified())));

      this.timer = new Timer();
      Date next = this.rc.getNextCheckDate(this.now);
      long perid = this.rc.getNextCheckMillis(next) - next.getTime();
      
      Debug.log("timer.schedule(next,perid): "+next +","+perid+"ms");
      _log = org.slf4j.LoggerFactory.getLogger(categoryName);
      this.timer.schedule(new RolloverFileTask(), next, perid);
    }
    else {
      LogLog.error("Either File or DatePattern options are not set for appender [" + 
        this.name + "].");
    }
  }

  void printPeriodicity(int type) {
    switch (type) {
    case 0:
      LogLog.debug("Appender [" + this.name + "] to be rolled every minute.");
      break;
    case 1:
      LogLog.debug("Appender [" + this.name + 
        "] to be rolled on top of every hour.");
      break;
    case 2:
      LogLog.debug("Appender [" + this.name + 
        "] to be rolled at midday and midnight.");
      break;
    case 3:
      LogLog.debug("Appender [" + this.name + "] to be rolled at midnight.");
      break;
    case 4:
      LogLog.debug("Appender [" + this.name + 
        "] to be rolled at start of week.");
      break;
    case 5:
      LogLog.debug("Appender [" + this.name + 
        "] to be rolled at start of every month.");
      break;
    default:
      LogLog.warn("Unknown periodicity for appender [" + this.name + "].");
    }
  }

  int computeCheckPeriod()
  {
    RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, 
      Locale.getDefault());

    Date epoch = new Date(0L);
    if (this.datePattern != null) {
      for (int i = 0; i <= 5; i++) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
          this.datePattern);
        simpleDateFormat.setTimeZone(gmtTimeZone);

        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 -1;
  }

  /**
   * old log LOGARCHIVE
   * log4j  locked http://blog.163.com/qiongling007@126/blog/static/214242962011102344916998/
   * log4j  time gen log file: http://www.iteye.com/topic/1006379
   * @throws IOException
   */
  void rollOver()
    throws IOException
  {
    if (this.datePattern == null) {
      this.errorHandler.error("Missing DatePattern option in rollOver().");
      return;
    }

    String datedFilename = this.fileName + this.sdf.format(this.now);
    
    //Debug.log("rollOver()  datedFilename: "+datedFilename);
    //Debug.log("rollOver()  scheduledFilename: "+scheduledFilename);
    if (this.scheduledFilename.equals(datedFilename)) {
      return;
    }

    closeFile();

    File target = new File(this.scheduledFilename);
    if (target.exists()) {
      System.out.println("scheduledFilename- exists- ");
      target.delete();
    }

    File file = new File(this.fileName);
    boolean result = file.renameTo(target);
    if (result)
      LogLog.debug(this.fileName + " -> " + this.scheduledFilename);
    else {
      LogLog.error("Failed to rename [" + this.fileName + "] to [" + 
        this.scheduledFilename + "].");
    }

    try
    {
      //setFile(this.fileName, true, this.bufferedIO, this.bufferSize);
      setFile(this.fileName, false, this.bufferedIO, this.bufferSize);
    } catch (IOException e) {
      this.errorHandler.error("setFile(" + this.fileName + ", false) call failed.");
    }
    this.scheduledFilename = datedFilename;
  }

  protected void subAppend(LoggingEvent event)
  {
    long n = System.currentTimeMillis();
    if (n >= this.nextCheck) {
      this.now.setTime(n);
      this.nextCheck = this.rc.getNextCheckMillis(this.now);
      try {
        rollOver();
      } catch (IOException ioe) {
//        if ((ioe instanceof InterruptedIOException)) {
//          Thread.currentThread().interrupt();
//        }
        LogLog.error("rollOver() failed.", ioe);
      }
    }
    super.subAppend(event);
    
    
  }
  
  
  
  
  class RolloverFileTask extends TimerTask {
	  
    RolloverFileTask() {
    	
    }

    public void run() {
    	/**
    	 * 通过定时打印日志,触发 subAppend(LoggingEvent event) 方法,进行日切日志文件归档。
    	 * mod by oyp 2014-12-04 18:22:30
    	 * @@@Time log cutting@@@
    	 */
    	try {
	    	 //Debug.log("-"+categoryName+"@@@-LOGARCHIVE-@@@ timing output log to generate a log file");
    		/**
    		 * log in system.log ,not in mpsp.log, because not the same layout
    		 */
	    	_log.info(Debug.LOGARCHIVE+" timing output log to generate a log file");
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
//    	System.out.println(System.currentTimeMillis()+"---------------------run---------------------");
//      long n = System.currentTimeMillis();
//      if (n >= UmpDailyRollingFileAppender.this.nextCheck) {
//        UmpDailyRollingFileAppender.this.now.setTime(n);
//        UmpDailyRollingFileAppender.this.nextCheck = UmpDailyRollingFileAppender.this.rc.getNextCheckMillis(UmpDailyRollingFileAppender.this.now);
//        try {
//          UmpDailyRollingFileAppender.this.rollOver();
//        } catch (IOException ioe) {
//          if ((ioe instanceof InterruptedIOException)) {
//            Thread.currentThread().interrupt();
//          }
//          LogLog.error("rollOver() failed.", ioe);
//          System.out.println(ioe);
//        }
//      }
    }
  }



public String getCategoryName() {
	return categoryName;
}

public void setCategoryName(String categoryName) {
	this.categoryName = categoryName;
}
}


2、重写 PatternLayout。

package com.pouyang.log4j;
/** 
 * @author ouyangping
 * @date Dec 4, 2014
 */
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.PatternConverter;
import org.apache.log4j.helpers.PatternParser;
import org.apache.log4j.spi.LoggingEvent;


public class UmpPatternLayout extends Layout
{
  public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
  public static final String TTCC_CONVERSION_PATTERN = "%r [%t] %p %c %x - %m%n";
  protected final int BUF_SIZE = 256;
  protected final int MAX_CAPACITY = 1024;

  private StringBuffer sbuf = new StringBuffer(256);
  private String pattern;
  private PatternConverter head;
  private String timezone;

  public UmpPatternLayout()
  {
    this("%m%n");
  }

  public UmpPatternLayout(String pattern)
  {
    this.pattern = pattern;
    this.head = createPatternParser(pattern == null ? "%m%n" : pattern).parse();
  }

  public void setConversionPattern(String conversionPattern)
  {
    this.pattern = conversionPattern;
    this.head = createPatternParser(conversionPattern).parse();
  }

  public String getConversionPattern()
  {
    return this.pattern;
  }

  public void activateOptions()
  {
  }

  public boolean ignoresThrowable()
  {
    return true;
  }

  protected PatternParser createPatternParser(String pattern)
  {
    return new PatternParser(pattern);
  }

  public String format(LoggingEvent event)
  {
    if (this.sbuf.capacity() > 1024)
      this.sbuf = new StringBuffer(256);
    else {
      this.sbuf.setLength(0);
    }

    PatternConverter c = this.head;
    
    while (c != null) {
      c.format(this.sbuf, event);
      c = c.next;
    }
    //System.out.println("layout2:"+this.sbuf.toString());
    //System.out.println("layout2:"+ MyUtil.bcd(this.sbuf.toString().getBytes()));
    /**
     * 过滤掉定时任务执行生成对账文件的日志,只打一个空串且不包含换行操作
     * add by oyp 2014-12-04 18:22:44
     */
//    String mesg = this.sbuf.toString();
//    Debug.log(mesg);
//    String[] temp = mesg.split("-");
//    if ( temp.length >= 2 && ( temp[1] == null || "".equals(temp[1].trim())) ) {
//    	return "";
//    } else {
//    	return mesg;
//    }
    
    String mesg = this.sbuf.toString();
    if (mesg.contains(Debug.LOGARCHIVE)) {
    	//Debug.log(mesg);
    	return "";
    } else {
    	return mesg;
    }
    //return this.sbuf.toString();
  }
}







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值