日志框架统一切换之(三):日志分割需求

一、需求

每天的日志按照一天四份的分割,即每天的6点、12点、18点、24点分割日志。

二、现状

目前的logback只是按照每月、日、半天、时、分切割,没有按照每隔6小时切割的配置支持(我知道的没有,请指教)

三、解决方案

之前使用过SizeAndTimeBasedFNATP来按照时间和文件大小分割日志;需求相似性首先想到通过扩展这个类来满足需求。

四、实施步骤

1、SizeAndTimeBasedFNATP源码理解(这里只看了几个从父类集成来的方法)

start方法:策略初始化的方法,在启动时初始化相关属性和方法;
isTriggeringEvent方法:触发器是否触发方法(核心)
getCurrentPeriodsFileNameWithoutCompressionSuffix:获取当前时期文件名的方法
比较重要的是第二个isTriggeringEvent方法

@Override
  public void start() {
    // 通过父类的start方法初始化相关属性
    super.start();
    //和压缩相关的API,暂不关注
    archiveRemover = createArchiveRemover();
    archiveRemover.setContext(context);

    // we need to get the correct value of currentPeriodsCounter.
    // usually the value is 0, unless the appender or the application
    // is stopped and restarted within the same period
    //主要用于初始化currentPeriodsCounter这个变量,这个变量是用来计算在指定时间间隔内第几个文件
    String regex = tbrp.fileNamePattern.toRegexForFixedDate(dateInCurrentPeriod);
    String stemRegex = FileFilterUtil.afterLastSlash(regex);


    computeCurrentPeriodsHighestCounterValue(stemRegex);

    started = true;
  }

public boolean isTriggeringEvent(File activeFile, final E event) {
    //检测当前时间是否超过下一个时间监测点,
    //如果超过,计算文件名(elapsedPeriodsFileName)、重置当前时期属性(dateInCurrentPeriod)、
    //计算下一个时间监测点(nextCheck)
    long time = getCurrentTime();
    if (time >= nextCheck) {
      Date dateInElapsedPeriod = dateInCurrentPeriod;
      elapsedPeriodsFileName = tbrp.fileNamePatternWCS
              .convertMultipleArguments(dateInElapsedPeriod, currentPeriodsCounter);
      currentPeriodsCounter = 0;
      setDateInCurrentPeriod(time);
      computeNextCheck();
      return true;
    }

    // for performance reasons, check for changes every 16,invocationMask invocations
    if (((++invocationCounter) & invocationMask) != invocationMask) {
      return false;
    }
    if (invocationMask < 0x0F) {
      invocationMask = (invocationMask << 1) + 1;
    }
    //文件大小检测,如果指定大小,增加currentPeriodsCounter
    if (activeFile.length() >= maxFileSize.getSize()) {
      elapsedPeriodsFileName = tbrp.fileNamePatternWCS
              .convertMultipleArguments(dateInCurrentPeriod, currentPeriodsCounter);
      currentPeriodsCounter++;
      return true;
    }

    return false;
  }

2、解决思路

从上面的源码解读中,我很快注意到了两个成员变量:
    dateInCurrentPeriod:当前所处的时期
    nextCheck:下一次检测时间
如果能把nextCheck每次推后6个小时,是否就满足我的需求了呢。

3、具体实施

a、新增一个SizeAndTimeBasedFNATP的子类DemoSizeAndTimeBasedFNATP。
b、添加一个int型成员变量:multiple,用于配制每次添加几个单元时间
c、重写计算nextCheck的方法computeNextCheck如下:
     protected void computeNextCheck() {
        nextCheck = rc.getRelativeDate(dateInCurrentPeriod,multiple).getTime();
     }

经过上述三步,我的扩展类变成如下:

import java.util.Calendar;
import java.util.Date;

import ch.qos.logback.core.joran.spi.NoAutoStart;
import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;

@NoAutoStart
public class DemoSizeAndTimeBasedFNATP<E> extends SizeAndTimeBasedFNATP<E> {
  private Integer multiple = 1;
  protected void computeNextCheck() {
        nextCheck = rc.getRelativeDate(dateInCurrentPeriod,multiple).getTime();
  }
  public Integer getMultiple() {
    return multiple;
  }
  public void setMultiple(Integer multiple) {
    if(multiple>1){
        this.multiple = multiple;
    }    
  }  
}

将此类配制到logback.xml中

      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${filePrefix}/demo-error.%d{yyyyMMddHHmm}.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="com.demo.utils.MlsPaySizeAndTimeBasedFNATP">
                 <multiple>10</multiple>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>

经过以上配置,日志文件变成了每隔6分钟一个分割。

似乎已经完成了我的需求,但是很快我发现了一个问题,那就是:

我中间停机3分钟,再次启动,其切割时间会向后平推。这不符合需求每天6点、12点、18点、24点切割的需求。

很快意识到是在启动时,dateInCurrentPeriod和nextCheck两个变量值初始化的问题。

因此决定在start方法中重新校正一下这两个参数的值,让dateInCurrentPeriod在启动时,初始化为所处时段的初始时间;
让nextCheck初始为所处时段的结束时间。

具体代码如下:

@Override
  public void start() {
    super.start();
    initCurrentPeriod(multiple);
    initNextCheck(multiple);
  }
  
  private void initCurrentPeriod(Integer multiple){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        switch (rc.getPeriodicityType()) {
          case TOP_OF_MINUTE:
              calendar.set(Calendar.SECOND, 0);
              calendar.set(Calendar.MILLISECOND, 0);
              calendar.set(Calendar.MINUTE, (calendar.get(Calendar.HOUR_OF_DAY)/multiple)*multiple);
              break;
          case TOP_OF_HOUR:
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            calendar.set(Calendar.HOUR_OF_DAY,(calendar.get(Calendar.HOUR_OF_DAY)/multiple)*multiple);
            break;

          case TOP_OF_DAY:
              calendar.set(Calendar.HOUR_OF_DAY, 0);
              calendar.set(Calendar.MINUTE, 0);
              calendar.set(Calendar.SECOND, 0);
              calendar.set(Calendar.MILLISECOND, 0);
              calendar.set(Calendar.DATE, (calendar.get(Calendar.HOUR_OF_DAY)/multiple)*multiple);
            break;
          default:
            throw new IllegalStateException("不支持倍数增加的单位");
        }
        
        dateInCurrentPeriod = calendar.getTime();
  }
  
  private void initNextCheck(Integer multiple){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        switch (rc.getPeriodicityType()) {
          case TOP_OF_MINUTE:
              calendar.set(Calendar.SECOND, 0);
              calendar.set(Calendar.MILLISECOND, 0);
              calendar.set(Calendar.MINUTE, (calendar.get(Calendar.HOUR_OF_DAY)/multiple+1)*multiple);
              break;
          case TOP_OF_HOUR:
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            calendar.set(Calendar.HOUR_OF_DAY,(calendar.get(Calendar.HOUR_OF_DAY)/multiple+1)*multiple);
            break;

          case TOP_OF_DAY:
              calendar.set(Calendar.HOUR_OF_DAY, 0);
              calendar.set(Calendar.MINUTE, 0);
              calendar.set(Calendar.SECOND, 0);
              calendar.set(Calendar.MILLISECOND, 0);
              calendar.set(Calendar.DATE, (calendar.get(Calendar.HOUR_OF_DAY)/multiple+1)*multiple);
            break;
          default:
            throw new IllegalStateException("不支持倍数增加的单位");
        }
        
        nextCheck = calendar.getTime().getTime();
  }

经过以上配置,再将logback中的配置改为每2小时分割,部署到测试环境,目前已经跑了一天了,看起来一切正常。



以上只是我个人的解决方法,对于logback了解不深,猜想应该有更完美的解决方案,希望各位不吝赐教和指正

转载于:https://my.oschina.net/bayuanqian/blog/205315

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值