Log4j2 打印日志实践
Apache Log4j 是一个基于 Java 的日志记录工具。它是由瑞士程序员 Ceki Gülcü 于 2001 年开发的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。Log4j 团队创建了 Log4j 的继任者,版本号为 2.0 的新版本。Log4j 2.0 着重于 Log4j 1.2、1.3、java.util.logging 和logback中的问题,并解决这些框架中的架构问题。此外,Log4j 2.0 提供了一个插件架构,这使得其更可扩展。Log4j 2.0 不是与 1.x 向后兼容的版本。
—— wikipedia
日志系统在整个项目架构设计中占得比例很重,比如管理员操作记录,一些捕获的异常记录等等。这时候有一个好的日志框架就是我们所必须的。目前最流行的是 Log4j 2.0 版本虽然前一段时间出了一个 0day 的 BUG 但是瑕不掩瑜。Log4j2 的配置也比较简单,支持 yml 、xml 甚至是 json 都是可以的。这个实践中我用的是 xml 格式,毕竟其他的没用过。
先来看下整体的配置,然后在根据每个标签单独研究。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" name="log4j2-name" monitorInterval="5">
<Properties>
<Property name="console.pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} - [%t] %-5level %logger{36} - %msg%n</Property>
<Property name="file.pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} - [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<Console name="console-appender" target="SYSTEM_OUT">
<PatternLayout pattern="${console.pattern}"/>
</Console>
<File name="files-appender" fileName="logs/files-appender.log" append="false">
<PatternLayout>
<Pattern>${file.pattern}</Pattern>
</PatternLayout>
</File>
<Async name="async-appender">
<AppenderRef ref="files-appender"/>
</Async>
<RandomAccessFile name="random-access-file-appender" fileName="logs/random-access-file.log">
<PatternLayout>
<Pattern>${file.pattern}</Pattern>
</PatternLayout>
</RandomAccessFile>
<RollingFile name="rolling-file-appender" fileName="logs/rolling-file-appender.log"
filePattern="logs/rolling-file-appender-INFO-%d{yyyy-MM-dd}_%i.log.gz">
<PatternLayout>
<Pattern>${file.pattern}</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="1MB"/>
</Policies>
</RollingFile>
<RollingRandomAccessFile name="rolling-random-access-file-appender"
fileName="logs/rolling-random-access-file.log"
filePattern="logs/$${date:yyyy-MM}/rolling-random-access-file-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>${file.pattern}</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="1 MB"/>
</Policies>
</RollingRandomAccessFile>
<!-- to 收件者 from 寄件者 -->
<SMTP name="mail-appender" subject="错误日志信息" to="发送到哪里" from="发送者"
smtpHost="smtp.qiye.163.com"
smtpPort="465"
bufferSize="1"
smtpUsername="SMTP用户名"
smtpPassword="SMTP密码"
smtpProtocol="smtps"
mail.smtp.ssl.enable="true"
mail.smtp.starttls.enable="true"
>
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout>
<Pattern>${file.pattern}</Pattern>
</PatternLayout>
</SMTP>
</Appenders>
<Loggers>
<logger name="org.mybatis" level="INFO"></logger>
<Root level="info">
<AppenderRef ref="console-appender"/>
<!-- <AppenderRef ref="file-appender"/>-->
<AppenderRef ref="rolling-file-appender"/>
<AppenderRef ref="async-appender"/>
<AppenderRef ref="random-access-file-appender"/>
<AppenderRef ref="rolling-random-access-file-appender"/>
<AppenderRef ref="mail-appender"/>
</Root>
</Loggers>
</Configuration>
上面是我常用的几个标签,每个标签都有其各自的意义。
Configuration
整个配置中最核心的标签,他对应 log4j 的 ConfigurationFactory
因为我用的是 xml 所以 ConfigurationFactory
会把配置传递给 XmlConfigurationFactory
,最常用的标签就是下面这些。
属性名称 | 描述 |
---|---|
name | 配置的名称。 |
status | 日志的等级,有"off", "trace", "debug", "info", "warn", "error", "fatal" 和 "all" ,选择 "trace" 就可以把 Log4j 的日志也显示出来 |
monitorInterval | 每隔多少秒更新日志的配置信息 |
Properties & Property
properties 这个标签很简单就是一个属性标签可以配置一些全局的属性,可以给后面的标签使用。
<Properties>
<Property name="属性名称"></Property>
</Properties>
Appenders
Appenders 单独没有什么作用,主要是他的各种子标签。下面子标签的属性是我常用的一些,如果不常用的可能没有列出来。
-
Console 日志通过控制台打印
Parameter Name Type Description layout Layout 输出格式化,可以使用 PatternLayout 标签替代 name String 标识符 target String "SYSTEM_OUT" or "SYSTEM_ERR". 默认为 "SYSTEM_OUT". <Console name="console-appender" target="SYSTEM_OUT"> <!--PatternLayout: 输出日志的格式--> <PatternLayout pattern=" %msg%n"/> <!--ThresholdFilter :日志输出过滤--> <!--level="info" :日志级别,onMatch="ACCEPT" :级别在info之上则接受,onMismatch="DENY" :级别在info之下则拒绝--> <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> </Console>
-
File 日志通过文件存储
Parameter Name Type Description append boolean 如果为 true ( 默认值),则记录将追加到文件末尾。如果设置为 false,则在写入新记录之前将清除该文件。 bufferedIO boolean 当 true 时 - 默认值,记录将写入缓冲区,并在缓冲区已满时将数据写入磁盘,或者,如果设置了立即Flush,则在写入记录时将数据写入磁盘。文件锁定不能与缓冲IO一起使用。性能测试表明,即使启用了即时浮现,使用缓冲 I/O 也能显著提高性能。 bufferSize int 当 bufferedIO 为 true 时,可以配置此项的缓冲区大小,默认值为 8192 字节。 fileName String 写入文件的名称,如果文件或者目录不存在会创建生成 name String Appender 标识符 <File name="files-appender" fileName="logs/files-appender.log" append="false"> <!--PatternLayout: 输出日志的格式 这种写法和上面那个等同--> <PatternLayout> <Pattern>${file.pattern}</Pattern> </PatternLayout> </File>
-
Async 和其他的 Appenders 配合使用,可以使得 Appenders 变为异步处理
Parameter Name Type Description name String 标识符 <Async name="async-appender"> <!--AppenderRef: 引用其他的 appender 使其成为异步处理--> <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> <AppenderRef ref="files-appender"/> </Async>
-
RandomAccessFile 和 File 是一样的只不过 RandomAccessFile 是始终是缓冲的而且不能关闭。据官方测量性能比 File 开启
bufferedIO
还要快 200%。内部使用的机制是 ByteBuffer + RandomAccessFile 而不是BufferedOutputStreamParameter Name Type Description append boolean 如果为 true ( 默认值),则记录将追加到文件末尾。如果设置为 false,则在写入新记录之前将清除该文件。 fileName String 要写入的文件的名称。如果文件或其任何父目录不存在,则将创建它们。 bufferSize int 缓冲区大小默认为 262144 字节 (256 * 1024)。 name String 标识符 <RandomAccessFile name="random-access-file-appender" fileName="logs/random-access-file.log"> <PatternLayout> <Pattern>${file.pattern}</Pattern> </PatternLayout> <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> </RandomAccessFile>
-
RollingFile 是一个 OutputStreamAppender,它写入 fileName 参数中指定的 File,并根据 TriggeringPolicy 和 RolloverPolicy 滚动文件。
Parameter Name Type Description append boolean 如果为 true ( 默认值),则记录将追加到文件末尾。如果设置为 false,则在写入新记录之前将清除该文件。 bufferedIO boolean 当 true 时 - 默认值,记录将写入缓冲区,并在缓冲区已满时将数据写入磁盘,或者,如果设置了立即Flush,则在写入记录时将数据写入磁盘。文件锁定不能与缓冲IO一起使用。性能测试表明,即使启用了即时浮现,使用缓冲 I/O 也能显著提高性能。 bufferSize int 当 bufferedIO 为 true 时,可以配置此项的缓冲区大小,默认值为 8192 字节。 fileName String 要写入的文件的名称。如果文件或其任何父目录不存在,则将创建它们。 name String 标识符 <RollingFile name="rolling-file-appender" fileName="logs/rolling-file-appender.log" filePattern="logs/rolling-file-appender-INFO-%d{yyyy-MM-dd}_%i.log.gz"> <PatternLayout> <Pattern>${file.pattern}</Pattern> </PatternLayout> <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> <Policies> <!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件 ,interval="6" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate="true" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点--> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <!-- SizeBasedTriggeringPolicy: 当文件超过设定的大小就开始滚动--> <SizeBasedTriggeringPolicy size="1MB"/> </Policies> </RollingFile>
-
RollingRandomAccessFile 和 RollingFile 是一样的,性能和 RandomAccessFile 差不多
Parameter Name Type Description append boolean 如果为 true ( 默认值),则记录将追加到文件末尾。如果设置为 false,则在写入新记录之前将清除该文件。 fileName String 要写入的文件的名称。如果文件或其任何父目录不存在,则将创建它们。 bufferSize int 当 bufferedIO 为 true 时,可以配置此项的缓冲区大小,默认值为 8192 字节。 name String 标识符 -
SMTP 通过邮箱发送日志信息
Parameter Name Type Description name String 标识符 from String 寄件者邮箱地址 replyTo String 以逗号分隔的接受者邮箱地址 to String 接受者邮箱地址 subject String 邮件的标题 bufferSize integer 当 bufferedIO 为 true 时,可以配置此项的缓冲区大小,默认值为 512。 smtpHost String SMTP HOST smtpPassword String SMTP 密码 smtpPort integer SMTP 端口 smtpProtocol String SMTP 传输协议 smtps 或 smtp 默认是 smtp smtpUsername String smtp 用户名 <SMTP name="mail-appender" subject="错误日志信息" to="发送到哪里" from="发送者" smtpHost="smtp.qiye.163.com" smtpPort="465" bufferSize="1" smtpUsername="SMTP用户名" smtpPassword="SMTP密码" smtpProtocol="smtps" mail.smtp.ssl.enable="true" mail.smtp.starttls.enable="true" > <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout> <Pattern>${file.pattern}</Pattern> </PatternLayout> </SMTP>
配置 SMTP 之后报错
main ERROR Could not create plugin of type class org.apache.logging.log4j.core.appender.SmtpAppender for element SMTP: java.lang.NoClassDefFoundError: javax/mail/Authenticator java.lang.NoClassDefFoundError: javax/mail/Authenticator
是应为没有找到 javax.mail 导入下面坐标即可。
<dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.5.0-b01</version> </dependency>
Loggers
<Loggers>
<logger name="org.springframework" level="INFO"></logger>
<Root level="info">
<AppenderRef ref="console-appender"/>
<!-- <AppenderRef ref="file-appender"/>-->
<AppenderRef ref="rolling-file-appender"/>
<AppenderRef ref="async-appender"/>
<AppenderRef ref="random-access-file-appender"/>
<AppenderRef ref="rolling-random-access-file-appender"/>
<AppenderRef ref="mail-appender"/>
</Root>
</Loggers>
使用 Logger 配置各种 Appenders ,Logger 必须指定一个包路径。还可以给这个包设置一个日志等级(TRACE、DEBUG、INFO、WARN、ERROR、ALL 或 OFF)。比如上面的 org.springframework
,如果未指定等级,默认为 ERROR。如果在标签内设置 additivity 属性如果为 true 则被该标签捕获的内容不会出现在 Root 节点。
<logger name="org.springframework" level="INFO"></logger>
Logger 也可以使用 AppenderRef 标签来指定输出位置和日志等级
<logger name="org.springframework" level="INFO">
<AppenderRef ref="console-appender" level="error"/>
</logger>
没有使用 logger 标签捕获到的内容或者没有设置additivity 为 true 的日志会出现在 Root 节点, Root 节点没有 additivity。
<Root level="info">
<AppenderRef ref="console-appender"/>
<!-- <AppenderRef ref="file-appender"/>-->
<AppenderRef ref="rolling-file-appender"/>
<AppenderRef ref="async-appender"/>
<AppenderRef ref="random-access-file-appender"/>
<AppenderRef ref="rolling-random-access-file-appender"/>
<AppenderRef ref="mail-appender"/>
</Root>
PatternLayout
上面一直出现的 PatternLayout 标签很明显是日志输出的格式。官方有一套自己的格式非常多,非常丰富。
%d:发生时间,%d{yyyy-MM-dd HH:mm:ss,SSS},输出类似:2020-02-20 22:10:28,921
%F:输出所在的类文件名
%t:线程名称
%p:日志级别
%c:日志消息所在类名
%m:消息内容
%M:输出所在函数名
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%l:执行的函数名(类名称:行号)com.core.LogHelper.aroundService(LogHelper.java:32)
%n:换行
%i:从1开始自增数字
%-5level:输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
${sys:user.home}是HOME目录 如:C:\Users\heave, 此处指定任意目录如:D:\logs
%highlight{} 高亮颜色 如:%highlight{%d [%t]}
%style{%d [%t]}{black} 设置高亮颜色 Red Green Yellow Blue Magenta Cyan White 还有一个 bold 高亮和其他颜色配合使用
例如: [%d{yyyy-MM-dd HH:mm:ss} %p][%c]: %m%n
更详细的可以查看官方手册 https://logging.apache.org/log4j/2.x/manual/layouts.html
部分内容来自:
[1]Log4j2 官网 https://logging.apache.org/log4j/2.x/
[2]Log4j2中文文档 https://www.docs4dev.com/docs/zh/log4j2/2.x/all/