了解log4j的源代码来源于项目中一次需求,我们想将系统所有的warn日志统一收集到common-warn.log的日志中去,以便于系统对其进行监控处理。于是模拟自动生成的error配置完成了warn的配置,但是测试发现common-warn.log中竟然有error日志,而且业务的正常日志中竟然也存在error和warn日志。这样相当于日志重复打了好多地方,无疑增加了日志量,同时增加了磁盘消耗。

原始配置:

 <appender name="DEFAULT-APPENDER" class="org.apache.log4j.DailyRollingFileAppender"><param name="file" value="${log_root}/${sys_host_name}/app-service.log"/><param name="append" value="true"/><param name="encoding" value="UTF-8"/><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern"value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/></layout></appender><!-- [公共Appender] 汇总错误 --><appender name="ERROR-APPENDER" class="org.apache.log4j.DailyRollingFileAppender"><param name="file" value="${log_root}/${sys_host_name}/common-error.log"/><param name="append" value="true"/><param name="encoding" value="UTF-8"/><param name="threshold" value="error"/>`<layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern"value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/></layout></appender><!-- [公共Appender] 汇总警告 --><appender name="WARN-APPENDER" class="org.apache.log4j.DailyRollingFileAppender"><param name="file" value="${log_root}/${sys_host_name}/common-warn.log"/><param name="append" value="true"/><param name="encoding" value="UTF-8"/><param name="threshold" value="WARN"/><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern"value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/></layout></appender><!-- [应用Logger]  - 默认 --><logger name="APP-LOG" additivity="false"><level value="${log_level}"/><appender-ref ref="DEFAULT-APPENDER"/><appender-ref ref="WARN-APPENDER"/><appender-ref ref="ERROR-APPENDER"/></logger>

  

所以我的核心诉求就是:将小于等于info的日志打印到app-service.log,将error打印到common-error.log, 将warn打印到common-warn.log。

1. Log4j核心类

核心抽象:

  • Logger 用于对日志记录行为的抽象,提供记录不同级别日志的统一接口;
  • Level对日志级别的抽象;
  • Appender是对记录日志形式的抽象,标示了日志打印的目的地;
  • Layout是对日志行格式的抽象;
  • LoggingEvent是对一次日志记录过程中所需要的信息的抽象,可以理解成一个上下文;

  整个日志打印的过程可以理解为Loger拿着LoggingEvent去找Appender, 让Appender按照Layout的形式将日志打印到指定的位置。 而Level起的啥作用呢? Logger和Appender都是有原则的不能说你让我打印我就打印,必须满足我的规则我才给你打印,这里的规则就是指Level(出来混都是要讲原则的)。

核对类图:

2. 初始化过程

  核心逻辑在LogManager的静态代码块,根据配置信息解析初始化Logger,Appender和Layout等核心组件;

3. 日志打印  

  核心的日志打印流程, 中间还有很多控制的细节,具体可以看源代码:

4. 日志控制

  回到我们的出发点,如何实现:
  将小于等于info的日志打印到app-service.log,将error打印到common-error.log, 将warn打印到common-warn.log。

  • 1. 重写Appender中2.5.2的方法(isAsSevereAsThreshold),自定义三个Appender的类,Appender1判断满足小于等于info的LoggingEvent才进行打印,目标指定为app-service.log;Appender2判断满足等于warn的LoggingEvent才进行打印,目标指定为common-warn.log;Appender3判断满足等于error的LoggingEvent才进行打印,目标指定为common-error.log;这样能够满足我们的需求,但是这样就会存两个问题

    • 存在一个潜规则就是:开发在配置的时候必须要使用自定义的Appender才可以满足,如果某同学使用默认的话,就可能存在日志打印错乱,影响监控;
    • 如果某个开发在Logger配置的时候忘记指定error的Appender,那么error日志将不会打印,存在日志丢失,风险很大;
  • 2. 添加2.5.3中提到的Filter配置,进行Appender过滤。log4j支持DenyAllFilter,LevelMatchFilter,LevelRangeFilter,StringMatchFilter的配置。通过LevelRangeFilter可以指定该Appender支持的日志范围。该方案解决了上个方案a存在的问题,但是无法解决b可能存在的问题;
  • 3. 重写Logger的日志打印的方法,在遍历Appender执行的时候,首先筛选出Level匹配(这里只相等)的Appender进行打印,如果没有匹配的Appender,再按照默认的策略进行打印。这样可以通过设置Appender的threshold即可实现,而且还可以防止Appender漏配置导致的日志缺失问题。该方案既可以兼容日志丢失,又可以满足我们的需求,但是logger对象中的AppenderAttachableImpl存储Appdender的List ,Logger中直接存放的是实现类,没有提供可扩展的方式,好像不太好实现。 求大神指点。

目前项目中使用的方案为2, 同时app-service.log的Appender不配置Filter默认接受error和warn的日志, 但是warn和error通过Fileter进行区分不会相互影响,这样可以满足业务监控warn和error日志的需求,不需要修改任何代码,同时满足不会丢失日志的问题。但是存在error和warn日志重复打印的问题。

最终的解决方案配置:

    <appender name="DEFAULT-APPENDER" class="org.apache.log4j.DailyRollingFileAppender"><param name="file" value="${log_root}/${sys_host_name}/app-default.log"/><param name="append" value="true"/><param name="encoding" value="UTF-8"/><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern"value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/></layout></appender><!-- [公共Appender] 汇总错误 --><appender name="ERROR-APPENDER" class="org.apache.log4j.DailyRollingFileAppender"><param name="file" value="${log_root}/${sys_host_name}/common-error.log"/><param name="append" value="true"/><param name="encoding" value="UTF-8"/><param name="threshold" value="error"/>`<!-- 仅打印error级别的日志 --><filter class="org.apache.log4j.varia.LevelRangeFilter"><param name="levelMin" value="ERROR" /><param name="levelMax" value="ERROR"/><param name="acceptOnMatch" value="true"/></filter><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern"value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/></layout></appender><!-- [公共Appender] 汇总警告 --><appender name="WARN-APPENDER" class="org.apache.log4j.DailyRollingFileAppender"><param name="file" value="${log_root}/${sys_host_name}/common-warn.log"/><param name="append" value="true"/><param name="encoding" value="UTF-8"/><param name="threshold" value="WARN"/><!-- 仅打印warn级别的日志 --><filter class="org.apache.log4j.varia.LevelRangeFilter"><param name="levelMin" value="WARN" /><param name="levelMax" value="WARN"/><param name="acceptOnMatch" value="true"/></filter><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern"value="%d [%X{loginUserEmail}/%X{loginUserID}/%X{remoteAddr}/%X{clientId} - %X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/></layout></appender><!-- [应用Logger]  - 默认 --><logger name="APP-LOG" additivity="false"><level value="${log_level}"/><appender-ref ref="DEFAULT-APPENDER"/><appender-ref ref="WARN-APPENDER"/><appender-ref ref="ERROR-APPENDER"/></logger>

  

Log4j源代码学习相关推荐

  1. php7.0 cli,PHP-7.1 源代码学习:php-cli 启动流程

    前言 php cli main 函数 configure & make 默认构建目标为 php-cli,相关代码在 sapi/cli 目录下,php_cli.c 文件中能够找到 main(入口 ...

  2. eos 源代码学习笔记一

    文章目录 eos 源代码学习笔记 1.eos 中的常见合约类型 2.语言环境局部( locale )变量的使用简介(目的是通过 gettext 软件包 来实现软件的全球化) 3.eos 源代码的一些优 ...

  3. BT源代码学习心得(十):客户端源代码分析(相关对象一览) -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(十):客户端源代码分析(相关对象一览) Author:wolfenstein(NeverSayNever), BitTorrent/download.py中的Multitorren ...

  4. BT源代码学习心得(一):总体描述 -- 转贴自wolfenstein (NeverSayNever)

    BT源代码学习心得(一):总体描述 发信人: wolfenstein (NeverSayNever), 个人文集 标  题: BT源代码学习心得(一):总体描述 发信站: 水木社区 (Fri Jul ...

  5. BT源代码学习心得(七):跟踪服务器(Tracker)的代码分析(HTTP协议处理对象) -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(七):跟踪服务器(Tracker)的代码分析(HTTP协议处理对象) author: wolfenstein (NeverSayNever) 上次我们分析了Tracker类初始化的 ...

  6. BT源代码学习心得(二):程序运行参数的获取 -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(二):程序运行参数的获取 发信人: wolfenstein (NeverSayNever), 个人文集 标  题: BT源代码学习心得(二):程序运行参数的获取 发信站: 水木社区 ...

  7. BT源代码学习心得(四):种子文件的生成 -- 转贴自wolfenstein (NeverSayNever)

    BT源代码学习心得(四):种子文件的生成 author: wolfenstein 在知道种子文件采取的编码方式后,我们现在可以来看一个种子文件具体是如何生成的了.在BT中,生成种子文件的可执行模块是 ...

  8. BT源代码学习心得(三):种子文件的编码方式 -- 转贴自wolfenstein (NeverSayNever)

    BT源代码学习心得(三):种子文件的编码方式 author: wolfenstein BT的作者使用了一种比较简单易懂的编码方式来对设计种子文件.这种编码方式能够很简单得对python中的各种数据类型 ...

  9. BT源代码学习心得(五):统一网络服务接口--RawServer -- 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(五):统一网络服务接口--RawServer author:wolfenstein 以后的部分都需要网络服务(种子文件的生成在本地就可以完成,但是通过这些种子文件下载实际的内容和提 ...

最新文章

  1. httpd启动不能加载模块
  2. 用python画出小人发射爱心_小人发射爱心biu简笔画表情-biu小人简笔画表情动态完整版-东坡下载...
  3. python常用关键字意思_python基础之常用关键字总结
  4. fibonacci数列的性质(ZOJ3707)
  5. 多种冒泡算法时间和效率比较
  6. 李国庆离开当当,广东消委会告长隆,智能校服提供定位功能,全球首个5G火车站来了,这就是今天的大新闻...
  7. Segment Descriptors, Code- and Data-Segment Descriptor Types
  8. P3667 [USACO17OPEN]Bovine Genomics
  9. 使用swfupload出现2049的错误原因
  10. 项目范围管理__范围管理计划 与 范围说明书
  11. summernote 富文本编辑器上传七牛云服务器
  12. 最全QQ盗号手法分析,全面防御QQ盗号
  13. VBA打开一个EXCEL文件并在二个文件之间来回操作的代码
  14. js自定义随机数插件:yiRan
  15. 什么软件可以测试手长,心率检测专家-可以让你通过按压手指检测出心率的健康app...
  16. [n年以前的诗] 怀念中XXXX年5月的泰山二首
  17. mysql 节假日判断_sql 节假日判断(春节、中秋、国庆、周末等)
  18. openpyxl 不支持xls文件,仅支持xlsx文件,xls用xlrd/xlwt
  19. 解决chrome您的连接不是私密连接
  20. 从中医角度体检健身标准

热门文章

  1. DOS系统里,分屏显示目录的命令是什么??
  2. 安全退出调用多个Activity的Application
  3. forget word a out 1
  4. Android内核开发:源码的版本与分支详解
  5. oracle 11g goldengate DML单向复制测试环境搭建
  6. JDK8新特性之Stream流
  7. 在if里赋值要注意=和==的优先级,==优先于=
  8. Excel的合并解析
  9. erlang的进程池。
  10. 政府和银行运维的差异