日志之log4j2和springboot


log4j2比logback好用。

现在之所有以spring采用logback,根据我个人的理解应该是某种非常特殊的理由。否则log4j2的性能比logback更好,且异步性能极好!

异步日志是log4j的最大有点,个人对此深有体会。异步对于系统的性能影响是很大的,事务的并发越多,log4j2对于性能的影响就越加明显。

本文主要讨论:

1.如何开启异步

2.如何让同一个类的日志根据级别输出到不同文件中,而且还不会重复

一、springboot集成log4j2

具体设定,到处都是,虽然如此,本文还是重复一遍从网友那里参考的内容。

1.引用log4j2,并排除默认的日志log-back

<dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-loggingartifactId>
                exclusion>
            exclusions>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-thymeleafartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-log4j2artifactId>
        dependency>
        
        <dependency>
            <groupId>com.lmaxgroupId>
            <artifactId>disruptorartifactId>
            <version>3.4.4version>
        dependency>

 注意:除了spring-boot-starter-web,还有一些artifactId(包标识)指定的包会包含spring-boot-starter-logging(内含Log-back).

所以,如果不好确认,那么可以使用sts或者idea的pom.xml查看器,查看是否包含spring-boot-starter-logging,如果有,那么就排除掉,否则log4j2无效。

2.application.yml/properties指定log4j2的配置

可以使用一些列的属性具体指定配置,但那样不方便,所以一般我们只指定一个属性

logging:
  config: classpath:log4j2.xml

然后在log4j2.xml中指定各种配置。

3.设置log4j2的内容

这个可以参考官方的资料 : https://logging.apache.org/log4j/2.x/manual/configuration.html

二、开启异步

关键在于设定logger(记录器)。

记录器可以通常设定三类记录器:同步、异步、控制台

此处略去同步和控制台。

下面是异步的部分参考:

<AsyncLogger name="com.hongcan.srv.basetest" additivity="false" includeLocation="true">
    <appender-ref ref="RollingFileInfo"  />
    <appender-ref ref="RollingFileDebug" />
    <appender-ref ref="RollingFileWarn"  />
    <appender-ref ref="RollingFileError" />
AsyncLogger>

注意:如果要为一个包或者具体类指定多个appender(写入器),那么必须如上指定,而不是一个包/类指定多个记录器(如果这样,只有一个会生效)。

          属性 additivity并非一直都是生效,要看appender的情况,includeLocation则建议设置为false。为了便于阅读,项目组在制定日志输出内容方面应该多花费一些心思。

三、不同级别日志输出到不同文件,且不重复

按照一般的设定(基本上是默认),级别高的日志会输出到所有文件,此类方式便于在一个文件查看所有的日志,这种方式便于调试和解决问题,但有时候也不太方便,因为内容实在太多了。

如果想达成这样的目的,那么可以如下设定:

<RollingFile name="RollingFileDebug" fileName="${file_path}/rolling-debug.log" 
                     filePattern="${file_path}/${backup_folder}/debug${backup_file_suffix}">
    
    <Filters>
        <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
    Filters>
    
    
    <PatternLayout pattern="${log_pattern}"/>
    <Policies>
        <TimeBasedTriggeringPolicy/>
        <SizeBasedTriggeringPolicy size="${file_max_size}"/>
    Policies>
    
    <DefaultRolloverStrategy max="10"/>
RollingFile>


<AsyncLogger name="com.hongcan.srv.basetest" additivity="false" includeLocation="true">
    <appender-ref ref="RollingFileInfo"  />
    <appender-ref ref="RollingFileDebug" />
    <appender-ref ref="RollingFileWarn"  />
    <appender-ref ref="RollingFileError" />
AsyncLogger>

 如果我们在指定类内部执行log.error("haha!"),那么这个内容会输出到debug,info,warn,error文件中。

如果不想这样,那么可以如下:

<RollingFile name="RollingFileDebug" fileName="${file_path}/rolling-debug.log" 
                     filePattern="${file_path}/${backup_folder}/debug${backup_file_suffix}">
    
    <Filters>
        <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
    Filters>
    
    
    <PatternLayout pattern="${log_pattern}"/>
    <Policies>
        <TimeBasedTriggeringPolicy/>
        <SizeBasedTriggeringPolicy size="${file_max_size}"/>
    Policies>
    
    <DefaultRolloverStrategy max="10"/>
RollingFile>


<AsyncLogger name="com.hongcan.srv.basetest" additivity="false" includeLocation="true">
    <appender-ref ref="RollingFileInfo"  />
    <appender-ref ref="RollingFileDebug" />
    <appender-ref ref="RollingFileWarn"  />
    <appender-ref ref="RollingFileError" />
AsyncLogger><configuration status="warn" monitorInterval="30">
    <Properties>
        
        <Property name="LOG_HOME">${sys:log.home}Property>
        
        <Property name="log_pattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
        
        <Property name="file_path" value="${sys:user.home}/logs/configservice-test"/>
        
        <Property name="file_max_size" value="10MB"/>
        
        <Property name="backup_folder" value="$${date:yyyy-MM}"/>
        
        
        <Property name="backup_file_suffix" value="-%d{yyyy-MM-dd}-%i.log.zip"/>
    Properties>


    
    <appenders>

        
        <console name="Console" target="SYSTEM_OUT">
            
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            
            <PatternLayout pattern="${log_pattern}"/>
        console>

        
        

        
        <RollingFile name="RollingFileDebug" fileName="${file_path}/rolling-debug.log" 
                     filePattern="${file_path}/${backup_folder}/debug${backup_file_suffix}">
            
            <Filters>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            Filters>
            
            
            <PatternLayout pattern="${log_pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${file_max_size}"/>
            Policies>
            
            <DefaultRolloverStrategy max="10"/>
        RollingFile>
        <RollingFile name="RollingFileInfo" fileName="${file_path}/rolling-info.log" 
                     filePattern="${file_path}/${backup_folder}/info${backup_file_suffix}">
            <Filters>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>                
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            Filters>
            
            <PatternLayout pattern="${log_pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${file_max_size}"/>
            Policies>
            
            <DefaultRolloverStrategy max="10"/>
        RollingFile>

        <RollingFile name="RollingFileWarn" fileName="${file_path}/rolling-warn.log" 
                     filePattern="${file_path}/${backup_folder}/warn${backup_file_suffix}">
            <Filters>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
            Filters>
            <PatternLayout pattern="${log_pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${file_max_size}"/>
            Policies>
        RollingFile>

        <RollingFile name="RollingFileError" fileName="${file_path}/rolling-error.log"  
                     filePattern="${file_path}/${backup_folder}/error${backup_file_suffix}">
            <Filters>
                <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            Filters>
            <PatternLayout pattern="${log_pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${file_max_size}"/>
            Policies>
        RollingFile>

    appenders>

    
    <loggers>
        <AsyncLogger name="com.hongcan.srv.basetest" additivity="false" includeLocation="true">
            <appender-ref ref="RollingFileInfo"  />
            <appender-ref ref="RollingFileDebug" />
            <appender-ref ref="RollingFileWarn"  />
            <appender-ref ref="RollingFileError" />
        AsyncLogger>
         
        <AsyncLogger name="io.netty" level="debug" additivity="false" includeLocation="true">
            <appender-ref ref="RollingFileDebug"/>
        AsyncLogger>

        
        <root level="all">
            <appender-ref ref="Console"/>
        root>

        
    loggers>

configuration>

关键的配置是这样的:


    
    
    
    

ThreholdFilter的属性 onMismatch的值 NEUTRAL决定了如何输出。

以上的配置就是这么一个意思,如果日志级别是ERROR,WARN,INFO的时候,那么就拒绝。如果不是,那么就让debug过滤器处理。

而debug过滤器的意思就是:如果匹配就接收,如果不匹配那么就拒绝!

四、控制台输出与调试

一般开发的时候,会要求控制台输出,要做到这一点非常简单,按照如下配置即可。


<appenders>
    
    <console name="Console" target="SYSTEM_OUT">
        
        <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
        
        <PatternLayout pattern="${log_pattern}"/>
    console>
appenders>


<loggers>
    
    <root level="all">
        <appender-ref ref="Console"/>
    root>
loggers>

分别定义好appender和logger即可。 通过控制level来控制控制台的输出。

如果使用springboot,那么可以通过多定义一个log4j的配置文件,例如定义为logj2-dev.xml,并在application-dev.properties中指定。

五、发送邮件

有时候,还需要发送邮件。

具体可以参考 https://blog.csdn.net/david_pfw/article/details/85846351

这里模仿了下:


<appenders>
    <SMTP name="Mail" subject="警告日志测试" to="lzfhope@163.com" from="lzfdev@163.com"
             smtpHost="smtp.163.com" 
             smtpPort="25"
             smtpPassword="xxxxxxx" 
             smtpProtocol="smtp"
             smtpUsername="lzfdev@163.com" 
             smtpDebug="true"
             bufferSize="50"
             >
             <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
        SMTP>
        
        <Async name="AsyncMail">
            <appender-ref ref="Mail"/>
        Async>
    
appenders>


<loggers>
    
    <root level="all">
        <appender-ref ref="Console"/>
        <appender-ref ref="AsyncMail"  />
    root>
loggers>

此外,要导入


        <dependency>
            <groupId>com.sun.mailgroupId>
            <artifactId>javax.mailartifactId>
            <version>1.6.2version>
        dependency>

如果配置都没有问题,还出现如下异常:

javax.mail.AuthenticationFailedException: 550 User has no permission

那么需要到163开启smtp权限,具体参考:https://blog.csdn.net/AngleFlyyy/article/details/107765541

然后,把这个提示的密码替换到配置文件中,假定这个密码是:UWPPVUQOPGDGWC00

那么log4j2.xml中对应如下:


<appenders>
<SMTP name="Mail" subject="警告日志测试" to="lzfhope@163.com" from="lzfdev@163.com" smtpHost="smtp.163.com" smtpPort="25" smtpPassword="UWPPVUQOPGDGWC00" smtpProtocol="smtp" smtpUsername="lzfdev@163.com" smtpDebug="true" bufferSize="50" > <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> SMTP> <Async name="AsyncMail"> <appender-ref ref="Mail"/> Async> appenders>

这样就可以发送邮件了,如下图:

如果还有问题,那么开启下调试: smtpDebug="true"

六、小结

logj4j2比较常会用就这些。但它的功能又远远不止这些!