您的位置:首页 > 编程语言 > Java开发

logback系列之四:输出日志到不同文件

2016-08-23 23:09 525 查看
实际生产中,每天都有大量的日志生成,单个文件(FileAppender)已经不能满足要求,RollingFileAppender继承了FileAppender,并提供了更多的功能: 
每天生成一个日志文件
将前一天的日志重命名为包含日期的格式
根据需要,删除过期历史日志

配置 

logback系列之二:输出日志到文件类似,改动的地方: 

1. logback[-test].xml文件: 

Java代码  


<appender name="rollingAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">  

    <file>/logs/heuristic.log</file>  

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  

        <fileNamePattern>/logs/heuristic-%d{yyyy-MM-dd}.log</fileNamePattern>  

        <maxHistory>30</maxHistory>  

    </rollingPolicy>  

    <encoder><!-- 必须指定,否则不会往文件输出内容 -->  

        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n</pattern>  

    </encoder>  

    <append>false</append>  

    <prudent>false</prudent>  

</appender>  

  

<root level="DEBUG">  

    <appender-ref ref="rollingAppender" />  

</root>  

调用测试类的方法,生成heuristic-2013-11-16.log文件。 

源码分析 

a. 如果指定了file属性,当天的文件名为file属性值(/logs/heuristic.log): 

ch.qos.logback.core.rolling.RollingFileAppender类 

Java代码  


public void start() {  

    ...  

    currentlyActiveFile = new File(getFile()); // 获取日志文件名  

}  

  

public String getFile() {  

    return rollingPolicy.getActiveFileName(); // 从滚动策略获取  

}  

上面logback[-test].xml的rollingPolicy配置为 
ch.qos.logback.core.rolling.TimeBasedRollingPolicy类 

看下实现: 

Java代码  


public String getActiveFileName() {  

  String parentsRawFileProperty = getParentsRawFileProperty();  

  if (parentsRawFileProperty != null) { // logback.xml指定了file属性  

    return parentsRawFileProperty; // 使用file值  

  } else {  

    return timeBasedFileNamingAndTriggeringPolicy  

        .getCurrentPeriodsFileNameWithoutCompressionSuffix();  

  }  

}  

  

public String getParentsRawFileProperty() {  

  return parent.rawFileProperty();  

}  

ch.qos.logback.core.FileAppender类 

Java代码  


final public String rawFileProperty() {  

  return fileName;  

}  

b. 必须指定TriggeringPolicy<E>和RollingPolicy,否则不会打印日志: 

看下 
ch.qos.logback.core.rolling.RollingFileAppender类: 

Java代码  


public void start() {  

  if (triggeringPolicy == null) {  

    addWarn("No TriggeringPolicy was set for the RollingFileAppender named "  

        + getName());  

    addWarn("For more information, please visit "+CODES_URL+"#rfa_no_tp");  

    return;  

  }  

  

  if (rollingPolicy == null) {  

    addError("No RollingPolicy was set for the RollingFileAppender named "  

        + getName());  

    addError("For more information, please visit "+CODES_URL+"rfa_no_rp");  

    return;  

  }  

TimeBasedRollingPolicy类实现了上面的两个接口,triggeringPolicy和rollingPolicy都指向TimeBasedRollingPolicy的实例对象。 

c. 如果file指定,前一天的文件名改为fileNamePattern的值(/logs/heuristic-2013-11-15.log)。 

通过设置TimeBasedRollingPolicy的maxHistory属性,可以控制已产生日志的数量。如果maxHistory设置为30,那么超过30天的log文件会被自动删除,这是通过RollingFileAppender的rollover()方法来实现的。 

该方法会调用 
ch.qos.logback.core.rolling.TimeBasedRollingPolicy类 
的rollover方法: 

Java代码  


public void rollover() throws RolloverFailure {  

  // 当此方法调用时,假定前一天日志文件已经关闭  

  String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy  

      .getElapsedPeriodsFileName();  

  

  String elpasedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName);  

  

  if (compressionMode == CompressionMode.NONE) {  

    if (getParentsRawFileProperty() != null) {  

      renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName); // file指定,重命名为fileNamePattern格式。如果目标文件存在,则重命名失败  

    } // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == null }  

  } else {  

    if (getParentsRawFileProperty() == null) {  

      future = asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elpasedPeriodStem); // file未指定,异步压缩  

    } else {  

      future = renamedRawAndAsyncCompress(elapsedPeriodsFileName, elpasedPeriodStem); // file指定,重命名并异步压缩  

    }  

  }  

  

  if (archiveRemover != null) {  

    archiveRemover.clean(new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime())); // 删除历史日志  

  }  

}  

默认的archiveRemover为ch.qos.logback.core.rolling.helper.DefaultArchiveRemover抽象类: 

Java代码  


public void clean(Date now) {  

  long nowInMillis = now.getTime();  

  int periodsElapsed = computeElapsedPeriodsSinceLastClean(nowInMillis);  

  lastHeartBeat = nowInMillis;  

  if (periodsElapsed > 1) {  

    addInfo("periodsElapsed = " + periodsElapsed);  

  }  

  // 从待删除日志的终止日期开始,每次回退一天,删除过期日志  

  for (int i = 0; i < periodsElapsed; i++) {  

    cleanByPeriodOffset(now, periodOffsetForDeletionTarget - i);  

  }  

}  

  

public void setMaxHistory(int maxHistory) {  

  // 待删除日志的终止日期:回退(maxHistory+1)天  

  this.periodOffsetForDeletionTarget = -maxHistory - 1;  

}  

cleanByPeriodOffset为抽象方法,这里交由 
ch.qos.logback.core.rolling.helper.TimeBasedArchiveRemover子类实现: 

Java代码  


protected void cleanByPeriodOffset(Date now, int periodOffset) {  

  Date date2delete = rc.getRelativeDate(now, periodOffset); // 计算需要删除日志的日期  

  String filename = fileNamePattern.convert(date2delete);  

  File file2Delete = new File(filename);  

  if (file2Delete.exists() && file2Delete.isFile()) {  

    file2Delete.delete(); // 删除文件  

    addInfo("deleting " + file2Delete);  

    if (parentClean) {  

      removeFolderIfEmpty(file2Delete.getParentFile());  

    }  

  }  

}  

d. 如果要启用压缩,需要将fileNamePattern的后缀名设置为压缩格式,如:/logs/heuristic-%d{yyyy-MM-dd}.zip。 

看下ch.qos.logback.core.rolling.RollingPolicyBase类相关的代码: 

Java代码  


protected void determineCompressionMode() {  

  if (fileNamePatternStr.endsWith(".gz")) {  

    addInfo("Will use gz compression");  

    compressionMode = CompressionMode.GZ;  

  } else if (fileNamePatternStr.endsWith(".zip")) {  

    addInfo("Will use zip compression");  

    compressionMode = CompressionMode.ZIP;  

  } else { // 如果后缀名不是.gz或.zip,不会启用压缩  

    addInfo("No compression will be used");  

    compressionMode = CompressionMode.NONE;  

  }  

}  

e. RollingFileAppender保证append的值为true,这样当天先写入的日志内容就不会丢失: 

ch.qos.logback.core.rolling.RollingFileAppender类的start()方法: 

Java代码  


if (!append) { // append为false时  

  addWarn("Append mode is mandatory for RollingFileAppender");  

  append = true; // 改成true  

}  

f. prudent模式不支持file设定;如果启用了压缩,logback将不会记录日志: 

ch.qos.logback.core.rolling.RollingFileAppender类 
的start()方法: 

Java代码  


if (isPrudent()) { // 安全模式,但效率低  

  if (rawFileProperty() != null) {  

    addWarn("Setting \"File\" property to null on account of prudent mode");  

    setFile(null); // 取消file属性设置  

  }  

  if (rollingPolicy.getCompressionMode() != CompressionMode.NONE) { // 启用了压缩  

    addError("Compression is not supported in prudent mode. Aborting");  

    return; // 返回,不会进行后面的记录日志操作  

  }  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  log4j logback Java