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>
    
  • RandomAccessFileFile 是一样的只不过 RandomAccessFile 是始终是缓冲的而且不能关闭。据官方测量性能比 File 开启 bufferedIO 还要快 200%。内部使用的机制是 ByteBuffer + RandomAccessFile 而不是BufferedOutputStream

    Parameter 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>
    
  • RollingRandomAccessFileRollingFile 是一样的,性能和 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/

posted @ 2022-03-01 23:35  奔跑的砖头  阅读(1335)  评论(0编辑  收藏  举报