log4j配置详解

Log4j配置属性详解、滚动日志配置,以及多种Appender输出配置示例 Log4j配置属性详解,以及滚动日志配置,以及多种Appdender输出配置示例 阅读详情
AI摘要

本文详细介绍了log4j的配置,包括依赖引入、配置文件、日志级别、appender配置,特别是DailyRollingFileAppender的使用。还讲解了如何自定义DailyRollingFileAppender实现自动删除过期日志的功能,以及配置中的关键参数和日志输出格式的定制。

目录

目录

# 一. 前言

1. 日志系列文章

2. 说明

二. log4j配置

1. log4j使用

1.1 依赖引入

1.2 添加配置文件

1.3 使用log4j打印日志

2. 常用配置示例(log4j.properties)

3. 配置说明

3.1 配置根logger 和 自定义logger

3.2 配置日志输出地appender

3.3 配置日志输出地的输出格式

3.4 其他常用配置

三. log4j源码

四. 拓展

1. 自定义DailyRollingFileAppender实现类, 自动删除过期日志



# 一. 前言

1. 日志系列文章

2. 说明

        本文使用log4j.properties展开讲解

二. log4j配置

1. log4j使用

1.1 依赖引入

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

1.2 添加配置文件

        log4j常用的配置文件有两种. 该文章后续都基于log4j.properties来讲解

  • log4j.xml
  • log4j.properties​​​

        其中, 两个文件并存时, 仅使用log4j.xml

        文件的配置信息见 [2. 常用配置示例]

1.3 使用log4j打印日志

package com.chenlongji.log4jstudy.controller;

import org.apache.log4j.Logger;

/**
 * @author clj
 */
public class LogTest {
    private static Logger logger = Logger.getLogger(LogTest.class);

    public static void main(String[] args) {
        // 注: 部分打印不出来, 那就是配置的日志级别太高
        logger.debug("这是debug级别的日志");
        logger.info("这是info级别的日志");
        logger.warn("这是warn级别的日志");
        logger.error("这是error级别的日志");
    }
}

2. 常用配置示例(log4j.properties)

        这里仅展示最常用的一些属性配置, 具体的配置请看 [3. 配置说明]

#是否打印log4j框架内的日志, 默认值为false
log4j.debug=false

# 配置根logger, 格式: [level],appenderName1,appenderName2,…
log4j.rootLogger=warn,console,errorDailyFile

# 配置自定义的logger, 格式: log4j.logger.[关注项目的包路径]
log4j.logger.com.chenlongji=info,console,infoRollingFile
# 打印时是否添加父类logger
log4j.additivity.com.chenlongji=false

#################
# 输出到控制台
#################
#console 控制台输出源
log4j.appender.console=org.apache.log4j.ConsoleAppender
# 输出日志的格式(布局)实现类
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# 输出日志的具体格式
log4j.appender.console.layout.conversionPattern=%d [%t] %-5p [%c\:%L] %m%n
# 输出日志的级别 不填则认为是ALL级别
log4j.appender.console.threshold=info

#################
# 输出到文件(RollingFileAppender类型)
#################
# 滚动文件输出源, 文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.infoRollingFile=org.apache.log4j.RollingFileAppender
# 输出文件的路径 例如:./src/logs/clj2023.log
log4j.appender.infoRollingFile.file=D://logs/info.log
# 文件最大容量(到达后创建新的文件), 默认值为10MB. 这里后缀可以为KB,MB,GB
log4j.appender.infoRollingFile.maxFileSize=500MB
# 输出日志的格式(布局)实现类. 注: layout必须是小写
log4j.appender.infoRollingFile.layout=org.apache.log4j.PatternLayout
# 输出日志的具体格式
log4j.appender.infoRollingFile.layout.conversionPattern=%d [%t] %-5p [%c\:%L] %m%n
# 输出日志的级别 不填则理解为ALL级别
log4j.appender.infoRollingFile.threshold=info

#################
# 输出到文件(DailyRollingFileAppender类型)
#################
# 按天滚动生成日志文件输出源
log4j.appender.errorDailyFile=org.apache.log4j.DailyRollingFileAppender
# 输出文件的路径 例如:./src/logs/error.log
log4j.appender.errorDailyFile.file=D://logs/error.log
# 输出日志的格式(布局)实现类
log4j.appender.errorDailyFile.layout=org.apache.log4j.PatternLayout
# 输出日志的具体格式
log4j.appender.errorDailyFile.layout.conversionPattern=%d [%t] %-5p [%c\:%L] %m%n
# 最小分隔为分钟, 设置小于分钟也是按分钟滚动生成文件
log4j.appender.errorDailyFile.datePattern='.'yyyy-MM-dd'.log'
# 输出日志的级别 不填则理解为ALL级别
log4j.appender.errorDailyFile.threshold=warn

3. 配置说明

配置文件主要部分就三个

  • 配置根logger 和 自定义logger
  • 配置日志输出地appender
  • 配置日志输出地的输出格式

需要了解的知识点

  • log4j支持的日志级别为(从高到低), 常用ERROR, WARN, INFO, DEBUG
           级别          level值
    • OFF          (2147483647)
    • FATAL       (50000)
    • ERROR    (40000)
    • WARN      (30000)
    • INFO        (20000)
    • DEBUG    (10000)
    • TRACE    (5000)
    • ALL          (-2147483648)

注:

  • 本文章log4j配置文件中的key的单词首字母都使用小写, 虽然log4j会将大写首字母转换, 但log4j部分单词是写死的(如layout是写死小写的). 
    全单词首字母小写示例: log4j.appender.console.threshold

3.1 配置根logger 和 自定义logger

  • logger的配置示例
     
    # 根logger
    log4j.rootLogger=warn,console
    
    
    # 自定义的logger
    log4j.logger.com.chenlongji=info,console
  •  根logger和自定义logger的关系

           a. 按绑定关系先执行本身logger下的所有appender, 若当前logger的additivity=false则结束
           b. 再执行父类的所有appender, 若当前logger的additivity=false则结束
           ....
          直到执行完rootLogger

    • 关系: 二者都是Logger类型
    • 绑定关系: 类似链表结构, 自定义logger的最终父节点为rootLogger
      哑节点logger   com.chenlongji.log4jstudy.controller.LogTest
             -- parent节点logger  com.chenlongji
                       -- parent节点logger  root
    • 执行顺序

                先执行com.chenlongji.log4jstudy.controller.LogTest 该logger的所有appender(日志级别必须大于等于当前输出的级别才会打印日志), 若当前logger的additive=false, 结束

                再执行com.chenlongji 该logger的所有appender, 若当前logger的additive=false, 结束

                ...

                最后执行root logger所有appender

  •  配置logger
    上面讲了绑定和执行关系, 这里讲logger的配置. 
    • 根logger配置
      • 格式: 
        log4j.rootLogger=[level],appenderName1,appenderName2,…
      • 示例:
        log4j.rootLogger=warn,console
      • 说明: (value无值时不报错, 但是logger无意义, 不讨论)
        • level为日记级别, 必填. 可选值: debug,info,warn,error, 大小写都可以
          • 注: level不填也不会报错, 但第一个appenderName会被跳过, 且level=debug
        • appenderName为appender的名字, 必填. 必须和appender名字大小写相同(appender下面再讲)
    • 自定义节点logger配置
      • 格式:
        log4j.logger.[包路径]=[level],appenderName1,appenderName2,…
      • 示例: 
        log4j.logger.com.chenlongji=info,console
      • 说明: (value无值时不报错, 但是logger无意义, 不讨论) 
        • level为日记级别, 必填. 可选值: debug,info,warn,error, 大小写都可以
          • 注: level不填也不会报错, 但第一个appenderName会被跳过, 且level=debug
        • appenderName为appender的名字, 必填. 必须和appender名字大小写相同(appender下面再讲)
      • 属性additive:
        • 属性值格式 
          log4j.additivity.[自定义logger的包路径]=[boolean值]
        • 示例:
          log4j.additivity.com.chenlongji=true
        • 说明:
          • 打印时是否添加父类logger, 非必填. 默认值为true
          • 为true时, 打印完本logger后, 会找父类logger继续执行, 直到某个logger的additive属性为false或找完所有

3.2 配置日志输出地appender

  1. 配置的格式
    格式: log4j.appender.[appender名称]=[appender实现类的全限定名]
    示例:
    # 滚动文件输出源, 文件大小到达指定尺寸的时候产生一个新的文件
    log4j.appender.infoRollingFile=org.apache.log4j.RollingFileAppender
    # 输出文件的路径 例如:./src/logs/clj2023.log
    log4j.appender.infoRollingFile.file=D://logs/info.log
    # 文件最大容量(到达后创建新的文件), 默认值为10MB. 这里后缀可以为KB,MB,GB
    log4j.appender.infoRollingFile.maxFileSize=500MB
    # 输出日志的格式(布局)实现类. 注: layout必须是小写
    log4j.appender.infoRollingFile.layout=org.apache.log4j.PatternLayout
    # 输出日志的具体格式
    log4j.appender.infoRollingFile.layout.conversionPattern=%d [%t] %-5p [%c\:%L] %m%n
    # 输出日志的级别 不填则理解为ALL级别
    log4j.appender.infoRollingFile.threshold=info
  2. appender常见类型
    1. ConsoleAppender  输出到控制台
    2. RollingFileAppender  滚动输出文件
    3. DailyRollingFileAppender  按日期滚动输出文件
  3. ConsoleAppender配置
    1. 属性name
      1. 示例值: log4j.appender.myConsole=org.apache.log4j.ConsoleAppender
      2. 必填性: 必填
      3. 默认值: 无
      4. 说明: 给appender取的名字
    2. 属性target
      1. 示例值: log4j.appender.myConsole.target=System.out
      2. 必填性: 非必填
      3. 默认值: System.out
      4. 说明: 输出的方式. 可选System.out或System.err
    3. 属性immediateFlush
      1. 示例值: log4j.appender.myConsole.immediateFlush=true
      2. 必填性: 非必填
      3. 默认值: true
      4. 说明: 是否立刻输出
    4. 属性encoding
      1. 示例值: log4j.appender.myConsole.encoding=UTF-8
      2. 必填性: 非必填
      3. 默认值: 系统默认字符集
      4. 说明: 输出内容的编码格式
    5. 属性layout
      1. 示例值: log4j.appender.myConsole.layout=org.apache.log4j.PatternLayout
      2. 必填性: 必填
      3. 默认值: 无
      4. 说明: 输出日志的格式(布局)实现类, 下面3.3再详细讲解
    6. 属性layout.conversionPattern
      1. 示例值: log4j.appender.myConsole.layout.conversionPattern=%d [%t] %-5p [%c\:%L] %m%n
      2. 必填性: 必填
      3. 默认值: 无
      4. 说明: 输出日志的具体格式, 下面3.3再详细讲解
    7. 属性threshold
      1. 示例值: log4j.appender.myConsole.threshold=info
      2. 必填性: 非必填
      3. 默认值: all
      4. 说明: 本appender的日志级别
  4. RollingFileAppender配置
    相同属性请查看ConsoleAppender配置
    1. 属性name
      1. 示例值: log4j.appender.myRollingFile=org.apache.log4j.RollingFileAppender
    2. 属性immediateFlush
    3. 属性encoding
    4. 属性layout
    5. 属性layout.conversionPattern
    6. 属性threshold
    7. 属性fileName
      1. 示例值: log4j.appender.myRollingFile.file=D://logs/info.log
      2. 必填性: 必填
      3. 默认值: 无
      4. 说明: 输出的文件名
    8. 属性fileAppend
      1. 示例值: log4j.appender.myRollingFile.append=true
      2. 必填性: 非必填
      3. 默认值: true
      4. 说明: 是否在文件尾追加日志, false则覆盖原内容
    9. 属性bufferIO
      1. 示例值: log4j.appender.myRollingFile.bufferIO=false
      2. 必填性: 非必填
      3. 默认值: false
      4. 说明: 是否开启缓冲区, 该值与immediateFlush互斥, 开启时immediateFlush会置为false
    10. 属性bufferSize
      1. 示例值: log4j.appender.myRollingFile.bufferSize=1024
      2. 必填性: 非必填
      3. 默认值: 8*1024
      4. 说明: 缓冲区大小
    11. 属性maxFileSize
      1. 示例值: log4j.appender.myRollingFile.maxFileSize=500MB
      2. 必填性: 非必填
      3. 默认值: 10*1024*1024 (10MB)
      4. 说明: 文件最大容量(到达后创建新的文件), 默认值为10MB. 这里后缀可以为KB,MB,GB. 单位大小写都可以
    12. 属性maxBackupIndex
      1. 示例值: log4j.appender.myRollingFile.maxBackupIndex=2
      2. 必填性: 非必填
      3. 默认值: 1
      4. 说明: 滚动文件的最大数, 例如MaxBackupIndex=2, 可以生成info.log1, info.log2, info.log三个文件
  5. DailyRollingFileAppender配置
    相同属性请查看上面其他Appender配置
    1. 属性name
      1. log4j.appender.myDailyFile=org.apache.log4j.DailyRollingFileAppender
    2. 属性immediateFlush
    3. 属性encoding
    4. 属性layout
    5. 属性layout.conversionPattern
    6. 属性threshold
    7. 属性fileName
    8. 属性fileAppend
    9. 属性bufferIO
    10. 属性bufferSize
    11. 属性datePattern
      1. 示例值: log4j.appender.myDailyFile.datePattern='.'yyyy-MM-dd'.log'
      2. 必填性: 非必填
      3. 默认值: '.'yyyy-MM-dd
      4. 说明: 文件日期格式, 也是分隔粒度. 最小分隔为分钟, 设置小于分钟也是按分钟滚动生成文件
  6. 自定义appender实现类
    见拓展

3.3 配置日志输出地的输出格式

        日志的输出格式. 实现类有

  1. EnhancedPatternLayout (PatternLayout 的增强版本, 不展开讲, 感兴趣的自行看下源码)
  2. HTMLLayout (html的格式, 输出 耗时 + 线程名 + 日志内容 +ogger名 + 日志内容等 )
  3. PatternLayout (通过设置模式, 个性化指定要输出的内容)
  4. SimpleLayout (简易模式, 只输出 日志级别 + 日志内容)
  5. TTCCLayout (输出 耗时 + 线程名 + 日志级别 + logger名 + ndc + 日志内容)
  6. XMLLayout (xml的格式, 输出 logger名 + 时间 +日志级别 + 线程名 + ndc + 日志内容等 )

        下面讲下最常用的PatternLayout的使用

  • 配置格式
    • log4j.appender.[appenderName].layout=[layout实现类的全限定名]
    • log4j.appender.[appenderName].layout.conversionPattern=[自定义的模式]
  • 示例
    # 输出日志的格式(布局)实现类
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    # 输出日志的具体格式
    log4j.appender.console.layout.conversionPattern=%d [%t] %-5p [%c\:%L] %m%n
  • 模式参数说明
    • %c: 输出日志的logger名, 即Logger.getLogger中的名字或全限定类名
    • %C: 输出日志消息产生时所在类的全限定类名
    • %d: 输出日志的时间格式, 默认格式为ISO8601(yyyy-MM-dd HH:mm:ss,SSS). 可在后面指定格式, 例如: %d{yyyy-MM-dd HH:mm:ss}
    • %F: 输出日志消息产生时所在的类文件名 (示例: LogTest.java)
    • %l: 输出日志的详细位置. 相当于%c.%M(%F:%L的组合),  示例: com.chenlongji.log4jstudy.controller.LogTest.testRolling(LogTest.java:24)
    • %L: 输出日志时所在的行数
    • %m: 输出日志的具体内容
    • %M: 输出日志所在类的方法名 (示例: testRolling)
    • %n: 输出当前系统的换行符
    • %p: 输出日志的级别
    • %r: 输出自日志程序启动到输出当前日志的耗时数. 没啥意义
    • %t: 输出日志产生的线程名
    • %x: 输出和当前线程相关联的NDC(嵌套诊断环境), 只能存储一个值
    • %X: 输出映射调试上下文信息, (使用map, 可以存储多个值). 常用于将traceId传递到日志中, 进行日志上下文搜索. 使用示例:  tid=%X{traceId}, 花括号内表示要取出值的key
      使用说明: 使用MDC跟踪日志_mdc日志_livel_java的博客-优快云博客
    • %%: 输出一个%号
    • [num]: 阿拉伯数字, 表示输出的长度
      • 示例 %5p, 表示输出日志级别, 占位为5, 多余长度补空格, 默认是右对齐
    • -[num]: 左对齐, 实际长度不足补空格, 实际长度超出也全显示
    • .[num]: 实际长度大于num会截掉左侧部分

3.4 其他常用配置

#是否打印log4j框架内的日志, 默认值为false
#log4j.debug=true

# 全局日志级别, 默认值为all, 设置后低于该级别的日志都不能输出
#log4j.threshold=info

三. log4j源码

        见文章 [log4j源码浅析]

四. 拓展

1. 自定义DailyRollingFileAppender实现类, 自动删除过期日志

步骤:

  1. 复制org.apache.log4j.DailyRollingFileAppender类, 创建MyDailyRollingFileAppender类
  2. 给新增的类添加 最大备份文件数属性maxBackupIndex, 并为其添加get和set方法
  3. 在rollOver() 方法中的 boolean result = file.renameTo(target); 之后添加移除过期文件逻辑方法removeFiles(File file)
  4. 实现removeFiles(File file) 方法
  5. 在配置文件中设置appender实现类 和 maxBackupIndex属性
    log4j.appender.myDailyFile.maxBackupIndex=5
    

修改点示例:

 

 

完整MyDailyRollingFileAppender代码:

package com.chenlongji.log4jstudy;

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

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author clj
 */
public class MyDailyRollingFileAppender extends FileAppender {


  // The code assumes that the following constants are in a increasing
  // sequence.
  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 int maxBackupIndex = 60;


  /**
     The date pattern. By default, the pattern is set to
     "'.'yyyy-MM-dd" meaning daily rollover.
   */
  private String datePattern = "'.'yyyy-MM-dd";

  /**
     The log file will be renamed to the value of the
     scheduledFilename variable when the next interval is entered. For
     example, if the rollover period is one hour, the log file will be
     renamed to the value of "scheduledFilename" at the beginning of
     the next hour. 

     The precise time when a rollover occurs depends on logging
     activity. 
  */
  private String scheduledFilename;

  /**
     The next time we estimate a rollover should occur. */
  private long nextCheck = System.currentTimeMillis () - 1;

  Date now = new Date();

  SimpleDateFormat sdf;

  RollingCalendar rc = new RollingCalendar();

  int checkPeriod = TOP_OF_TROUBLE;

  // The gmtTimeZone is used only in computeCheckPeriod() method.
  static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");


  /**
     The default constructor does nothing. */
  public MyDailyRollingFileAppender() {
  }

  /**
    Instantiate a <code>MyDailyRollingFileAppender</code> and open the
    file designated by <code>filename</code>. The opened filename will
    become the ouput destination for this appender.

    */
  public MyDailyRollingFileAppender(Layout layout, String filename,
                                    String datePattern) throws IOException {
    super(layout, filename, true);
    this.datePattern = datePattern;
    activateOptions();
  }

  /**
     The <b>DatePattern</b> takes a string in the same format as
     expected by {@link SimpleDateFormat}. This options determines the
     rollover schedule.
   */
  public void setDatePattern(String pattern) {
    datePattern = pattern;
  }

  /** Returns the value of the <b>DatePattern</b> option. */
  public String getDatePattern() {
    return datePattern;
  }

    /**
     Set the maximum number of backup files to keep around.
     <p>The <b>MaxBackupIndex</b> option determines how many backup
     files are kept before the oldest is erased. This option takes
     a positive integer value. If set to zero, then there will be no
     backup files and the log file will be truncated when it reaches
     <code>MaxFileSize</code>.
     */
    public void setMaxBackupIndex(int maxBackups) {
        this.maxBackupIndex = maxBackups;
    }

    public int getMaxBackupIndex(){
        return maxBackupIndex;
    }

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

    } else {
      LogLog.error("Either File or DatePattern options are not set for appender ["
		   +name+"].");
    }
  }

  void printPeriodicity(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).

  int computeCheckPeriod() {
    RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());
    // set sate to 1970-01-01 00:00:00 GMT
    Date epoch = new Date(0);
    if(datePattern != null) {
      for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
	SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
	simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT
	String r0 = simpleDateFormat.format(epoch);
	rollingCalendar.setType(i);
	Date next = new Date(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...
  }

  /**
     Rollover the current file to a new file.
  */
  void rollOver() throws IOException {

    /* 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 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 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+"].");
    }

    // 删除文件
    removeFiles(file);

    try {
      // This will also close the file. This is OK since multiple
      // close operations are safe.
      this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
    }
    catch(IOException e) {
      errorHandler.error("setFile("+fileName+", true) call failed.");
    }
    scheduledFilename = datedFilename;
  }

    /**
   * This method differentiates MyDailyRollingFileAppender from its
   * super class.
   *
   * <p>Before actually logging, this method will check whether it is
   * time to do a rollover. If it is, it will schedule the next
   * rollover time and then rollover.
   * */
  @Override
  protected void subAppend(LoggingEvent event) {
    long n = System.currentTimeMillis();
    if (n >= nextCheck) {
      now.setTime(n);
      nextCheck = rc.getNextCheckMillis(now);
      try {
	rollOver();
      }
      catch(IOException ioe) {
          if (ioe instanceof InterruptedIOException) {
              Thread.currentThread().interrupt();
          }
	      LogLog.error("rollOver() failed.", ioe);
      }
    }
    super.subAppend(event);
   }

    /**
     * 删除文件
     */
    private void removeFiles(File file) {
        //获取日志文件列表,控制数量,实现清理策略
        try{
            if (file.getParentFile().exists()){
                File[] files = file.getParentFile().listFiles(new LogFileFilter(file.getName()));
                if (files == null) {
                    return;
                }
                Long[] dateArray = new Long[files.length];
                for (int i = 0; i < files.length; i++) {
                    File fileItem = files[i];
                    String fileDateStr = fileItem.getName().replace(file.getName(), "");
                    try {
                        Date fileDate = sdf.parse(fileDateStr);
                        long fileDateLong = fileDate.getTime();
                        dateArray[i] = fileDateLong;
                    } catch (ParseException e) {
                        LogLog.error("Parse File Date Throw Exception : " + e.getMessage());
                    }
                }
                Arrays.sort(dateArray);
                if (dateArray.length > maxBackupIndex) {
                    for (int i = 0; i < dateArray.length - maxBackupIndex; i++) {
                        String dateFileName = file.getPath() + sdf.format(dateArray[i]);
                        File dateFile = new File(dateFileName);
                        Files.delete(dateFile.toPath());
                    }
                }
            }
        } catch (Exception e){
            errorHandler.error("removeFiles failed." + e.getMessage());
        }
    }

    /**
     * 文件过滤器
     */
    class LogFileFilter implements FileFilter {
        private String logName;

        public LogFileFilter(String logName) {
            this.logName = logName;
        }

        @Override
        public boolean accept(File file) {
            if (logName == null || file.isDirectory()) {
                return false;
            } else {
                LogLog.debug(file.getName());
                return file.getName().startsWith(logName);
            }
        }
    }

}

/**
 *  RollingCalendar is a helper class to MyDailyRollingFileAppender.
 *  Given a periodicity type and the current time, it computes the
 *  start of the next interval.  
 * */
class RollingCalendar extends GregorianCalendar {
  private static final long serialVersionUID = -3560331770601814177L;

  int type = MyDailyRollingFileAppender.TOP_OF_TROUBLE;

  RollingCalendar() {
    super();
  }  

  RollingCalendar(TimeZone tz, Locale locale) {
    super(tz, locale);
  }  

  void setType(int type) {
    this.type = type;
  }

  public long getNextCheckMillis(Date now) {
    return getNextCheckDate(now).getTime();
  }

  public Date getNextCheckDate(Date now) {
    this.setTime(now);

    switch(type) {
    case MyDailyRollingFileAppender.TOP_OF_MINUTE:
	this.set(Calendar.SECOND, 0);
	this.set(Calendar.MILLISECOND, 0);
	this.add(Calendar.MINUTE, 1);
	break;
    case MyDailyRollingFileAppender.TOP_OF_HOUR:
	this.set(Calendar.MINUTE, 0);
	this.set(Calendar.SECOND, 0);
	this.set(Calendar.MILLISECOND, 0);
	this.add(Calendar.HOUR_OF_DAY, 1);
	break;
    case MyDailyRollingFileAppender.HALF_DAY:
	this.set(Calendar.MINUTE, 0);
	this.set(Calendar.SECOND, 0);
	this.set(Calendar.MILLISECOND, 0);
	int hour = get(Calendar.HOUR_OF_DAY);
	if(hour < 12) {
	  this.set(Calendar.HOUR_OF_DAY, 12);
	} else {
	  this.set(Calendar.HOUR_OF_DAY, 0);
	  this.add(Calendar.DAY_OF_MONTH, 1);
	}
	break;
    case MyDailyRollingFileAppender.TOP_OF_DAY:
	this.set(Calendar.HOUR_OF_DAY, 0);
	this.set(Calendar.MINUTE, 0);
	this.set(Calendar.SECOND, 0);
	this.set(Calendar.MILLISECOND, 0);
	this.add(Calendar.DATE, 1);
	break;
    case MyDailyRollingFileAppender.TOP_OF_WEEK:
	this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
	this.set(Calendar.HOUR_OF_DAY, 0);
	this.set(Calendar.MINUTE, 0);
	this.set(Calendar.SECOND, 0);
	this.set(Calendar.MILLISECOND, 0);
	this.add(Calendar.WEEK_OF_YEAR, 1);
	break;
    case MyDailyRollingFileAppender.TOP_OF_MONTH:
	this.set(Calendar.DATE, 1);
	this.set(Calendar.HOUR_OF_DAY, 0);
	this.set(Calendar.MINUTE, 0);
	this.set(Calendar.SECOND, 0);
	this.set(Calendar.MILLISECOND, 0);
	this.add(Calendar.MONTH, 1);
	break;
    default:
	throw new IllegalStateException("Unknown periodicity type.");
    }
    return getTime();
  }
}

日志框架 --- Log4j log4j是一个流行的Java日志框架,是由 Apache 的一个开源项目。它允许开发人员通过将日志语句插入应用程序代码中来记录应用程序运行时的事件。它能够控制通过哪些目标输出的消息以及每个目标的格式。log4j主要是由 Logger,Appender,Layout 组成,Logger,日志记录器,控制日志的输出级别以及是否输出日志。Appender,控制日志被写入的位置,例如控制台、文件等。Layout,用于定义日志输出的格式。 阅读详情

相关推荐

log4j漏洞分析及总结

2021年12月8号爆出的log4j2的远程代码执行漏洞【cve-2021-44228】,堪称史诗级核弹漏洞,虽然过了这么久,大部分现网中的相关漏洞已经修复,但任然可以捡漏…,网上也有不少大佬和研究机构都对该漏洞做了分析和复盘,年前年后比较忙,一直没有好好的分析总结该漏洞,最近学习下刚好补上。 漏洞描述及影响 log4j是Apache的一个开源项目,是一个基于Java的日志记录框架。Log4j2是log4j的后继者,被大量用于业务系统开发,记录日志信息。很多互联网公司以及耳熟能详的公司的系统都在使用该框架。

csd_ct的专栏 5万+

LOG4J的配置文件

Log4J的配置文件

qq_44861126的博客 4123

【项目实战】日志系统Log4j配置文件(Configuration File)详解

2)配置放在文件里,通过命令行参数传递文件名字,通过PropertyConfigurator.configure(args[x])解析并配置;输出格式通过PatternLayout设为"%-4r [%t] %-5p %c %x - %m%n",4)配置放在文件里,通过应用服务器配置传递文件名等信息,利用一个特殊的servlet来完成配置。3)配置放在文件里,通过环境变量传递文件名等信息,利用log4j默认的初始化过程解析并配置;采用类似C语言中的printf函数的打印格式格式化日志信息。

奶爸的编程之路,也就一周冷个三天 1411

Log4j详细配置

一、配置根rootLogger 用于配置当前日志输出的级别以及输出的位置 语法: log4j.rootLogger = [level],appenderName1,appenderName2,… level设置检测的日志记录的优先级, 优先级由低到高分为OFF,TRACE,DEBUG,INFO,WARN,ERROR,FATAL,ALL Log4j 建议只使用四个级别,优先级从低到高分别是DEBUG,INFO,WARN,ERROR DEBUG:输出调试性质的内容 INFO:记录系统关键信息 WA

璃尔 ° 的博客 7425

基于Unidbg的小红书加密协议动态分析与算法还原实战

在移动应用安全领域,加密协议与签名机制是保障数据传输安全、实现客户端身份验证的核心技术。其原理通常涉及哈希算法、对称/非对称加密以及自定义的混淆逻辑,旨在防止请求被篡改或重放。理解这些协议对于安全研究、风控策略制定及合规的数据交互分析具有重要价值。在实际的工程实践中,面对高度混淆和加固的Native代码(SO库),传统的静态分析往往难以深入。此时,沙盒模拟执行技术提供了一种动态、可控的分析方案。通过搭建一个虚拟的移动应用运行环境,研究人员可以在无需真机、规避反调试机制的情况下,完整地追踪和观察加密算法的执行

weixin_29315091的博客 323

金属粘结剂喷射3D打印技术:工艺流程与后处理关键

金属粘结剂喷射(Binder Jetting)是一种创新的增材制造技术,通过逐层喷射粘合剂将金属粉末粘结成型,再经过脱脂和烧结等后处理工序获得最终零件。这项技术的核心优势在于无需支撑结构、可实现批量生产,并且材料利用率高。在3D打印领域,金属BJ技术特别适合中小尺寸、结构复杂且表面质量要求高的零件生产。其工艺流程包括前期数据处理、打印生胚阶段、拆包与清粉,以及关键的渗透、脱脂和烧结后处理环节。后处理工艺的控制直接决定了零件的机械性能和尺寸精度,其中烧结工艺尤为关键,需要精确控制温度曲线和气氛环境。金属BJ打

weixin_35751194的博客 83

log4j和log4j2配置详解

文章目录1 log4j或log4j2配置详解1.1 pom.xml文件1.2 log4j.properties的引用1.3 log4j.properties的说明1.3.1 rootLogger文件1.3.2 输出目的地appender文件1.3.2.1 ConsoleAppender1.3.2.2 FileAppender1.3.2.3 DailyRollingFileAppender1.3.2...

上善若泪 6093

从零上手HiAgent:构建能听懂指令的智能体框架实战指南

智能体(Agent)作为人工智能领域的重要范式,正从传统的预设流程自动化转向以目标驱动的自主规划与执行。其核心原理在于利用大语言模型(LLM)作为决策大脑,通过任务规划、工具调用与记忆机制,将模糊的自然语言指令转化为可执行的工作流。这一技术显著提升了人机协作的效率和自然度,其价值在自动化办公、数据分析与智能流程编排等场景中尤为突出。本文聚焦于HiAgent这一具体框架,深入解析其作为智能体开发平台的核心架构,涵盖规划器、执行器、工具集等关键组件,并提供从环境配置、自定义工具开发到复杂任务链构建的完整工程实践

weixin_29266007的博客 881

Log4j2配置详解

一、背景 最近由于项目的需要,需要将日志全部迁移成log4j2版本,之前对于项目日志的配置总是似懂非懂,最近详细整理了下知识点,本文就作为一个记录来详细记录一下log4j2配置的相关知识点。 二、配置详解 ...

Hinbo的博客 3万+

gnuradio+b210实现FM收音机

gnuradio+b210实现FM收音机环境介绍FM接收1 Flow Graph2 变量参数FM发射1 Flow Graph 环境介绍 Name Version gnuradio 3.7.14.0 uhd 3.15.0.0 ubuntu 18.04 usrp b210 参考 https://www.ijedr.org/papers/IJEDR1702038.pdf Audio File Transmission using GNURADIO and USRP FM接

u011745228的博客 5124

【我的Android进阶之旅】Android自定义View实现一个游戏摇杆,来实现监听遥动的方向或者监听摇动的角度的功能

一、需求描述 去年有个需求,需要使用自定义View实现一个游戏摇杆,来识别上下左右摇动的方向。 有点类似下面这样的王者荣耀游戏摇杆的效果 二、业界已有的参考资料 在下面这篇博客介绍了如何自定义游戏摇杆 2.1 博客介绍 Android自定义摇杆 2.1.1 功能 支持自适应大小 支持2个方向、4个方向、8个方向的摇动监听 支持摇动角度获取 可选回调模式 支持可摇动区域自定义 支持摇杆自定义 支持设置图片、色值、Shape图形 2.1.2 效果图 2.1.3 设置回调方式 setCallBac

字节卷动 1407

java Log4j日志配置详解大全

java Log4j日志配置详解大全 一、Log4j简介 Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局)。这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松地记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。 1、Loggers Loggers组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的,DEBUG < INFO &

weixin_43805579的博客 6955

多体动力学分析软件:SIMPACK_(17).SIMPACK高级编程与脚本

自定义力和约束可以用于模拟更复杂和现实的物理场景。SIMPACK 提供了接口,允许用户通过 Python 脚本来实现自定义力和约束。以下是一个示例,展示如何定义一个自定义力函数并应用于模型。# 定义自定义力函数"""自定义力函数:param t: 时间:param position: 位置:param velocity: 速度:return: 力"""# 创建一个新的 SIMPACK 模型# 添加一个刚体# 添加一个关节# 添加一个自定义力# 设置仿真参数# 运行仿真。

kkchenjj的博客 1418

Log4j.properties配置详解【log4j配置文件】

文章目录一、 Log4j简介1.1 Loggers1.2 Appenders1.3 Layouts二、配置详解2.1 配置根Logger:2.2 配置日志信息输出目的地(appender)2.3 配置日志信息的输出格式(Layout)Log4j比较全面的配置输出独立日志文件 一、 Log4j简介 Log4j有三个主要的组件: Loggers(记录器):日志类别和级别; Appenders (输出源):日志要输出的地方; Layouts(布局):日志以何种形式输出 1.1 Loggers Loggers组件在

qq_43842093的博客 4万+

【unity实战】Unity2D TileMap的探究(最简单,最全面的TileMap使用介绍)

之前有人在微信上找我,问了TileMap相关的知识【unity实战】随机地下城生成2——绘制地图Tilemap的使用及一些技巧的使用(含源码)不过写的不是特别不是特别细致,只是简单的用了一下,所有这次特地打算单独写一篇文章,来介绍一下,下次还有人问我,我直接就把这篇文章丢给他,完美!Unity的Tilemap 一般称之为瓦片地图或者平铺地图,是 Unity2017 中新增的功能,主要用于快速编辑 2D 游戏中的场景,通过复用资源的形式提升地图多样性。Tilemap是一个用于创建2D地图的工具。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 1万+

YOLOv8改进 | Neck篇 | Slim-Neck替换特征融合层实现超级涨点 (又轻量又超级涨点)

本文给大家带来的改进机制是Slim-neck提出的Neck部分,Slim-neck是一种设计用于优化卷积神经网络中neck部分的结构。在我们YOLOv8中,neck是连接主干网络(backbone)和头部网络(head)的部分,负责特征融合和处理,以便提高检测的准确性和效率。亲测在小目标检测和大尺度目标检测的数据集上都有大幅度的涨点效果(mAP直接涨了大概有0.4左右。同时本文对Slim-Neck的框架原理进行了详细的分析,不光让大家会添加到自己的模型在写论文的时候也能够有一定的参照。

Snu77的博客 1万+

Log4j的配置与使用详解

Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,我们可以控制每条日志的输出格式;只需要通过一个配置文件就可以灵活的配置,而不需要修改任何代码。

龙源IT 的博客 3万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

log4j2配置详解

log4j2配置详解一、关于配置文件的名称以及在项目中的存放位置二、缺省默认配置文件三 、配置详细介绍1.Configuration根节点2.Appenders节点(1)Console子节点(2)File子节点(3)RollingFile子节点(4)Async子节点(5)其他非常用输出源(6)PatternLayout3.Loggers节点(1)Root子节点(2)Logger子节点4.Properties子节点5.配置过滤器< Filters >6.AsyncLogger7.关于日志level

weixin_52189442的博客 1300

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Log4j2配置文件详解

转载:https://blog.youkuaiyun.com/ThinkWon/article/details/101629302 Configuration 根节点,有status和monitorInterval等多个属性 status的值有 “trace”, “debug”, “info”, “warn”, “error” and “fatal”,用于控制log4j2日志框架本身的日志级别,如果将stratus设置为较低的级别就会看到很多关于log4j2本身的日志,如加载log4j2配置文件的路径等信息 mo

孤云博客 5522

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Log4j配置详解

在强调可重用组件开发的今天,除了自己从头到尾开发一个可重用的日志操作类外,Apache为我们提供了一个强有力的日志操作包-Log4j。 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志...

wang20051的专栏 204

Spark log4j 日志配置详解

一、spark job日志介绍 spark中提供了log4j的方式记录日志。可以在$SPARK_HOME/conf/下,将 log4j.properties.template 文件copy为 log4j.properties 来启用log4j配置。但这个配置为全局配置,不能单独配置某个job的运行日志。 在Spark的conf目录下,把log4j.properties.templa...

Jacy_Wang的博客 1129

Log4j日志配置详解

Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIXSyslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

iflink 4593

log4j配置详解(非常详细)

log4j配置详解(非常详细) Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的,它可接key=value格式的设置或xml格式的设置信息。通过配置,可以创建出Log4J的运行环境。 配置文件 Log4J配置文件的基本格式如下: #配置根Logger log4j.rootLogger = [ level ] , appenderName1 , appenderName2 , … #配置日志信息输出目的地Appender log4j.a

孤独冰刃的博客 2万+

log4j配置文件详解

Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的,它可接key=value格式的设置或xml格式的设置信息。通过配置,可以创建出Log4J的运行环境。 1. 配置文件 Log4J配置文件的基本格式如下: #配置根Logger log4j.rootLogger = [ level ] , appenderName , appen...

satomiyo的博客 2万+
上一篇: @DateTimeFormat失效原因
下一篇: log4j源码浅析
陈*^_^*
博客等级 码龄6年 48粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值