[关闭]
@Otokaze 2018-11-28T04:21:49.000000Z 字数 7171 阅读 488

Log4j 笔记

Java

Log4j 简介

Apache Log4j 曾经是最流行的 Java 日志组件,它有两个大版本:1.x 和 2.x。log4j 1.x 早在 2012 就已经停止更新,Apache 在此之后憋了好久,然后开发出了 log4j 2.x(借鉴了不少 logback 的新理念),憋了这么久开发出来的 2.x 版本当然是很优秀的,据说比 log4j 1.x 和 logback 的性能要高出好几倍(异步)。

之前我们学习了 logback 和 slf4j,logback 和 log4j 1.x 的作者其实是同一个人,这位大佬之所以会选择开发一个新的日志框架(logback),听说是因为与 Apache 存在意见分歧,具体什么矛盾我也没仔细研究过。

SLF4J 是一个日志门面框架,而 Logback 是一个日志组件,可以将它们简单的理解为 接口 与 实现类。之所以要抽象出一个 slf4j 门面,是为了提高程序的可移植性和可定制性,使用了 slf4j 之后,如果我想换过一个底层的日志组件,比如从 logback 换为 log4j 2.x,我们只需要更换 jar 包,然后使用新的配置文件就行,而我们的程序代码是不需要做任何更改的,这符合开闭原则(对扩展开放,对修改关闭)。

而 Apache 其实也有一个日志门面框架,叫做 Jakarta Commons Logging (JCL),但是很不幸,JCL 和 log4j 1.x 都死得比较早,jcl 在 2014 年就停止更新了,而 log4j 1.x 在 2012 年停止更新。

虽然 log4j 1.x 已经停止更新这么长时间了,但是 log4j 的大名恐怕每个 Java 程序员都有所耳闻,并且目前还有很多应用都还在使用 log4j 1.x,比如 Apache Tomcat。甚至还有新的应用继续选择使用 log4j 1.x。

对于 log4j 2.x,目前暂时没有学习的计划,鉴于 log4j 1.x 还有这么多项目在用,所以本文也是主要介绍 log4j 1.2(2012 年发布的最后一个版本,使用 properties 属性文件作为配置文件格式)。

Log4j 介绍

和大多数日志组件一样,log4j 也由三个主要组件:Logger、Appender、Layout:

Logger 的层次结构
与 logback 意义,log4j 的 logger 之间也是存在层次结构的,并且它们的机构是相似的,都是按照 java 全限定类名的格式来定义父级 logger 和子级 logger,比如名为 com.zfl9 的 logger 是名为 com.zfl9.util 的 logger 的直接父级,反之,com.zfl9.util 是 com.zfl9 的直接子级。

这个树状层次结构中,有一个根节点,那就是 root logger,根记录器,就好比 Java 中的所有类的祖先类是 Object 类一样。我们可以通过 org.apache.log4j.Logger.getRootLogger() 方法来获取 root logger。

Logger 类的基本方法:

  1. package org.apache.log4j;
  2. public class Logger {
  3. // Creation & retrieval methods:
  4. public static Logger getRootLogger();
  5. public static Logger getLogger(String name);
  6. public static Logger getLogger(Class<?> clazz);
  7. // printing methods:
  8. public void trace(Object message);
  9. public void debug(Object message);
  10. public void info(Object message);
  11. public void warn(Object message);
  12. public void error(Object message);
  13. public void fatal(Object message);
  14. // generic printing method:
  15. public void log(Level l, Object message);
  16. }

因为 logger 的名称是有意义的,并且存在层级关系,所以一个最佳实践是,使用当前类的全限定类名作为 logger 的名称,logger 的静态工厂方法提供了一个便捷方法,允许我们直接传递 java.lang.Class 对象,logger 内部会自动使用 Class 对象的 name 作为 logger 的 name,即全限定类名作为 logger 的名称。

logger 提供 6 个级别的日志记录方法(级别由低到高):

其中 trace 和 fatal 不建议使用,所以常用的 4 个级别为:debug、info、warn、error。

与 logback 一样,log4j 的 logger 层级关系当然是有特殊用途的,不然单纯定义一个层级关系没有实际意义,这个意义就是,父 logger 上的 appender 会被子 logger 所继承。而 root logger 是最顶层的 logger,所以 root logger 上的 appender 会被所有 logger 所继承(除非明确指定不继承)。

其实除了 log4j 的配置文件格式与 logback 不同之外,其他的概念都是相辅相成的,毕竟是同一人写的。

Log4j 配置

和 logback 不同,log4j 没有所谓的默认配置,所以如果你没有提供配置文件,log4j 在运行时会报错。log4j 的配置文件格式为 *.properties java 属性文件,所谓属性文件就是一行一个 name = value 键值对而已,格式非常简单,和我们通过 JVM 运行参数 -Dprop.name=prop.value 指定是一样的。

log4j 的默认配置文件名为 log4j.properties,在运行时,log4j 会在 class path 路径中查找此文件。

root logger 配置

  1. log4j.rootLogger = [level], appenderName1, appenderName2, ...
  2. # level 为日志记录级别,取值 OFF|TRACE|DEBUG|INFO|WARN|ERROR|FATAL|ALL
  3. # Log4j 建议只使用四个级别,优先级从低到高分别是 DEBUG, INFO, WARN, ERROR

appender 配置

  1. log4j.appender.appenderName = fully.qualified.name.of.appender.class
  2. log4j.appender.appenderName.optionN = valueN
  3. #
  4. # Log4j 提供的 appender 有以下几种:
  5. # - org.apache.log4j.ConsoleAppender 输出至控制台
  6. # - org.apache.log4j.FileAppender 输出至磁盘文件
  7. # - org.apache.log4j.DailyRollingFileAppender 日志文件按日期轮转
  8. # - org.apache.log4j.RollingFileAppender 日志文件按大小轮转
  9. #
  10. # ConsoleAppender 属性
  11. # - Threshold = DEBUG 指定日志消息的有效记录级别
  12. # - ImmediateFlush = true 默认为 true,所有的消息都会被立即输出
  13. # - Target = System.err 默认为 System.out,输出到 STDOUT/STDERR
  14. #
  15. # FileAppender 属性
  16. # - Threshold = INFO 指定日志消息的有效日志级别
  17. # - ImmediateFlush = true 默认为 true,所有的消息都会被立即输出
  18. # - File = C:\log4j.log 指定消息输出到 'C:\log4j.log' 文件路径
  19. # - Append = false 默认为 true,追加到源文件,而非覆盖源文件
  20. # - Encoding = UTF-8 可以指定文件编码格式,建议使用 UTF-8 编码
  21. #
  22. # DailyRollingFileAppender 属性
  23. # - Threshold = WARN 指定日志消息的有效日志级别
  24. # - ImmediateFlush = true 默认为 true,所有的消息都会被立即输出
  25. # - File = C:\log4j.log 指定消息输出到 'C:\log4j.log' 文件路径
  26. # - Append = false 默认为 true,追加到源文件,而非覆盖原文件
  27. # - Encoding = UTF-8 可以指定文件编码格式,建议使用 UTF-8 编码
  28. # - DatePattern=$PATTERN 轮转周期,这个 pattern 是已归档文件的后缀
  29. # - '.'yyyy-MM 每月
  30. # - '.'yyyy-ww 每周
  31. # - '.'yyyy-MM-dd 每天
  32. # - '.'yyyy-MM-dd-a 每半天
  33. # - '.'yyyy-MM-dd-HH 每小时
  34. # - '.'yyyy-MM-dd-HH-mm 每分钟
  35. #
  36. # RollingFileAppender 属性
  37. # - Threshold = WARN 指定日志消息的有效日志级别
  38. # - ImmediateFlush = true 默认为 true,所有的消息都会被立即输出
  39. # - File = C:\log4j.log 指定消息输出到 'C:\log4j.log' 文件路径
  40. # - Append = false 默认为 true,追加到源文件,而非覆盖原文件
  41. # - Encoding = UTF-8 可以指定文件编码格式,建议使用 UTF-8 编码
  42. # - MaxFileSize = 100KB 单个日志文件的最大大小,可用单位:KB,MB,GB
  43. # - MaxBackupIndex = 10 要保留的已归档日志文件的数量,超过的将被删除

layout 配置

  1. log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
  2. log4j.appender.appenderName.layout.optionN = valueN
  3. #
  4. # Log4j 提供的 layout 有以下几种:
  5. # - org.apache.log4j.PatternLayout
  6. #
  7. # PatternLayout 属性
  8. # - ConversionPattern = %m%n 格式字符串
  9. #
  10. # %m 日志消息
  11. # %p 日志级别
  12. # %c 记录器名称
  13. # %t 当前线程名
  14. # %d 当前的时间,默认 `%d{yyyy-MM-dd HH:mm:ss,SSS}`
  15. # %n 一个换行符
  16. # %% 一个百分号
  17. #
  18. # 在 % 与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式:
  19. # %5c 输出 logger 名称,最小宽度是 5,右对齐
  20. # %-5c 输出 logger 名称,最小宽度是 5,左对齐
  21. # %.5c 输出 logger 名称,最大宽度是 5,会截断

Log4j 例子

pom.xml

  1. <dependency>
  2. <groupId>log4j</groupId>
  3. <artifactId>log4j</artifactId>
  4. <version>1.2.17</version>
  5. </dependency>

log4j.properties(普通)

  1. log4j.rootLogger = TRACE, STDOUT, FILE
  2. log4j.appender.STDOUT = org.apache.log4j.ConsoleAppender
  3. log4j.appender.STDOUT.Threshold = TRACE
  4. log4j.appender.STDOUT.ImmediateFlush = true
  5. log4j.appender.STDOUT.Target = System.out
  6. log4j.appender.STDOUT.layout = org.apache.log4j.PatternLayout
  7. log4j.appender.STDOUT.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n
  8. log4j.appender.FILE = org.apache.log4j.FileAppender
  9. log4j.appender.FILE.Threshold = TRACE
  10. log4j.appender.FILE.ImmediateFlush = true
  11. log4j.appender.FILE.File = D:/TEMP/log4j.log
  12. log4j.appender.FILE.Append = true
  13. log4j.appender.FIlE.Encoding = UTF-8
  14. log4j.appender.FILE.layout = org.apache.log4j.PatternLayout
  15. log4j.appender.FILE.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n

Main.java

  1. package com.zfl9;
  2. import org.apache.log4j.Logger;
  3. public class Main {
  4. public static void main(String[] args) {
  5. Logger logger = Logger.getLogger(Main.class);
  6. logger.trace("trace message");
  7. logger.debug("debug message");
  8. logger.info("info message");
  9. logger.warn("warn message");
  10. logger.error("error message");
  11. logger.fatal("fatal message");
  12. }
  13. }

运行结果:

  1. 2018-11-28 12:08:28.758 [TRACE] com.zfl9.Main - trace message
  2. 2018-11-28 12:08:28.759 [DEBUG] com.zfl9.Main - debug message
  3. 2018-11-28 12:08:28.759 [INFO ] com.zfl9.Main - info message
  4. 2018-11-28 12:08:28.759 [WARN ] com.zfl9.Main - warn message
  5. 2018-11-28 12:08:28.759 [ERROR] com.zfl9.Main - error message
  6. 2018-11-28 12:08:29.046 [FATAL] com.zfl9.Main - fatal message

日志文件:

  1. 2018-11-28 12:08:28.758 [TRACE] com.zfl9.Main - trace message
  2. 2018-11-28 12:08:28.759 [DEBUG] com.zfl9.Main - debug message
  3. 2018-11-28 12:08:28.759 [INFO ] com.zfl9.Main - info message
  4. 2018-11-28 12:08:28.759 [WARN ] com.zfl9.Main - warn message
  5. 2018-11-28 12:08:28.759 [ERROR] com.zfl9.Main - error message
  6. 2018-11-28 12:08:29.046 [FATAL] com.zfl9.Main - fatal message

日志轮转
log4j.properties(轮转)

  1. log4j.rootLogger = TRACE, STDOUT, FILE
  2. log4j.appender.STDOUT = org.apache.log4j.ConsoleAppender
  3. log4j.appender.STDOUT.Threshold = TRACE
  4. log4j.appender.STDOUT.ImmediateFlush = true
  5. log4j.appender.STDOUT.Target = System.out
  6. log4j.appender.STDOUT.layout = org.apache.log4j.PatternLayout
  7. log4j.appender.STDOUT.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n
  8. log4j.appender.FILE = org.apache.log4j.DailyRollingFileAppender
  9. log4j.appender.FILE.Threshold = TRACE
  10. log4j.appender.FILE.ImmediateFlush = true
  11. log4j.appender.FILE.File = D:/TEMP/log4j.log
  12. log4j.appender.FILE.Append = true
  13. log4j.appender.FIlE.Encoding = UTF-8
  14. log4j.appender.FILE.DatePattern = '.'yyyy-MM-dd-HH-mm-ss
  15. log4j.appender.FILE.layout = org.apache.log4j.PatternLayout
  16. log4j.appender.FILE.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c - %m%n

产生的日志文件名:

  1. log4j.log
  2. log4j.log.2018-11-28-12-15-01
  3. log4j.log.2018-11-28-12-16-00

当前活动的文件为 log4j.log,已归档的文件就是后面两个。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注