zoukankan      html  css  js  c++  java
  • 【log4j2】springboot使用log4j2详细配置

    本文主要讲解:

    1、一个日志配置文件如何拆分

    2、不同服务的日志如何划分

    3、日志如何滚动

    4、日志过期策略

    5、异步日志

    1、日志拆分

    日志配置文件拆分,例如以下完整的日志配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration status="DEBUG">
    
        <properties>
            <!--日志格式-->
            <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %X{TRACE_ID} [%thread] %-5level %logger[%L] - %m%n"/>
            <!--日志编码-->
            <property name="CHARSET" value="utf-8"/>
            <!--单个日志文件大小-->
            <property name="MAX_FILE_SIZE" value="200MB"/>
            <!--日志保存时间-->
            <property name="MAX_HISTORY" value="P30D"/>
            <!--日志根路径-->
            <property name="BASE_LOG_PATH" value="/data/logs"/>
            <!--日志应用名,例如拼接完整的日志路径:/data/logs/app/app-info.log-->
            <property name="SERVER_NAME" value="${sys:SERVICE_NAME}"/>
        </properties>
    
    
        <appenders>
            <Console name="CONSOLE" target="SYSTEM_OUT">
                <PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
            </Console>
    
            <RollingRandomAccessFile name="FILE-INFO"
                                     fileName="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-info.log"
                                     filePattern="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-info.%d{yyyy-MM-dd}-%i.log.gz">
                <LevelRangeFilter minLevel="WARN" maxLevel="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
                <PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
                <Policies>
                    <!--每天滚动一次-->
                    <TimeBasedTriggeringPolicy interval="1"/>
                    <!--或者日志达到10KB 滚动一次-->
                    <SizeBasedTriggeringPolicy size="10KB"/>
                </Policies>
                <!--日志删除策略-->
                <DefaultRolloverStrategy fileIndex="nomax">
                    <Delete basePath="${BASE_LOG_PATH}/${SERVER_NAME}" maxDepth="2">
                        <IfFileName glob="*-info.*.log.gz"/>
                        <IfLastModified age="P1D"/>
                    </Delete>
                </DefaultRolloverStrategy>
            </RollingRandomAccessFile>
    
            <RollingRandomAccessFile name="FILE-ERROR"
                                     fileName="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-error.log"
                                     filePattern="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-error.%d{yyyy-MM-dd}-%i.log.gz">
                <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
                <PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
                <Policies>
                    <!--每天滚动一次-->
                    <TimeBasedTriggeringPolicy interval="1"/>
                    <!--或者日志达到10KB 滚动一次-->
                    <SizeBasedTriggeringPolicy size="10KB"/>
                </Policies>
                <!--日志删除策略-->
                <DefaultRolloverStrategy fileIndex="nomax">
                    <Delete basePath="${BASE_LOG_PATH}/${SERVER_NAME}" maxDepth="2">
                        <IfFileName glob="*-error.*.log.gz"/>
                        <IfLastModified age="P1D"/>
                    </Delete>
                </DefaultRolloverStrategy>
            </RollingRandomAccessFile>
        </appenders>
    
        <loggers>
            <AsyncRoot level="DEBUG" includeLocation="true" >
                <AppenderRef ref="CONSOLE"/>
            </AsyncRoot>
            <AsyncLogger name="com.luna" level="INFO" includeLocation="true" >
                <appender-ref ref="FILE-INFO"/>
                <appender-ref ref="FILE-ERROR"/>
            </AsyncLogger>
            <AsyncLogger name="druid.sql.Statement" level="DEBUG" additivity="false" includeLocation="true" >
                <appender-ref ref="CONSOLE"/>
                <appender-ref ref="FILE-INFO"/>
            </AsyncLogger>
        </loggers>
    </configuration>

    在单个项目中这个配置文件可以直接使用,但是在聚合项目中,我们不可能在每个项目都写一遍完整的日志配置文件。如果这样做,1,容易写错造成日志格式的不统一、2,假如你更改了日志配置,需要更改多个配置文件容易遗漏

    所以我们常规做法是将这些公共的配置抽取出来,然后直接引用即可。log4j2的日志拆分和其它日志拆分基本差不多(logback,log4j),官方文档:http://logging.apache.org/log4j/2.x/manual/configuration.html#XInclude

    从官方文档看出,log4j2的拆分,依赖XInclude

    新建log4j-xinclude-property.xml,抽取Properties

    <?xml version="1.0" encoding="UTF-8"?>
    
    <properties>
        <!--日志格式-->
        <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %X{TRACE_ID} [%thread] %-5level %logger[%L] - %m%n"/>
        <!--日志编码-->
        <property name="CHARSET" value="utf-8"/>
        <!--单个日志文件大小-->
        <property name="MAX_FILE_SIZE" value="200MB"/>
        <!--日志保存时间-->
        <property name="MAX_HISTORY" value="P30D"/>
        <!--日志根路径-->
        <property name="BASE_LOG_PATH" value="/data/logs"/>
        <!--日志应用名,例如/data/logs/app/app-info.log-->
        <property name="SERVER_NAME" value="${sys:SERVICE_NAME}"/>
    </properties>

    新建log4j-xinclude-appenders.xml,抽取appenders

    <?xml version="1.0" encoding="UTF-8"?>
    
    <appenders>
        <Console name="CONSOLE" target="SYSTEM_OUT">
            <PatternLayout pattern="${PATTERN}" charset="${CHARSET}"/>
        </Console>
    
        <RollingRandomAccessFile name="FILE-INFO"
                                 fileName="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-info.log"
                                 filePattern="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-info.%d{yyyy-MM-dd}-%i.log.gz">
            <LevelRangeFilter minLevel="WARN" maxLevel="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${PATTERN}" charset="${CHARSET}" />
            <Policies>
                <!--每天滚动一次-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <!--或者日志达到10KB 滚动一次-->
                <SizeBasedTriggeringPolicy size="10KB"/>
            </Policies>
            <!--日志删除策略-->
            <DefaultRolloverStrategy fileIndex="nomax">
                <Delete basePath="${BASE_LOG_PATH}/${SERVER_NAME}" maxDepth="2">
                    <IfFileName glob="*-info.*.log.gz"/>
                    <IfLastModified age="P1D"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingRandomAccessFile>
    
        <RollingRandomAccessFile name="FILE-ERROR"
                                 fileName="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-error.log"
                                 filePattern="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-error.%d{yyyy-MM-dd}-%i.log.gz">
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${PATTERN}" charset="${CHARSET}" />
            <Policies>
                <!--每天滚动一次-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <!--或者日志达到10KB 滚动一次-->
                <SizeBasedTriggeringPolicy size="10KB"/>
            </Policies>
            <!--日志删除策略-->
            <DefaultRolloverStrategy fileIndex="nomax">
                <Delete basePath="${BASE_LOG_PATH}/${SERVER_NAME}" maxDepth="2">
                    <IfFileName glob="*-error.*.log.gz"/>
                    <IfLastModified age="P1D"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingRandomAccessFile>
    
    </appenders>

    新建log4j-xinclude-loggers.xml,抽取loggers

    <?xml version="1.0" encoding="UTF-8"?>
    
    <loggers>
    
        <AsyncRoot level="DEBUG" includeLocation="true" >
            <AppenderRef ref="CONSOLE"/>
        </AsyncRoot>
    
    
        <AsyncLogger name="com.luna" level="INFO" includeLocation="true" >
            <appender-ref ref="FILE-INFO"/>
            <appender-ref ref="FILE-ERROR"/>
        </AsyncLogger>
    
        <AsyncLogger name="druid.sql.Statement" level="DEBUG" additivity="false" includeLocation="true" >
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="FILE-INFO"/>
        </AsyncLogger>
    
    </loggers>

    最后新建log4j2.xml引用即可

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration xmlns:xi="http://www.w3.org/2001/XInclude"
                   status="DEBUG" name="XIncludeDemo">
    
        <!--常量配置-->
        <xi:include href="log4j-xinclude-property.xml"/>
        <!--appenders-->
        <xi:include href="log4j-xinclude-appenders.xml" />
        <!--loggers-->
        <xi:include href="log4j-xinclude-loggers.xml" />
    
    
    </configuration>

    完整的目录结构

    image

     

    2、不同服务的日志如何划分

    例如,order(订单系统),goods(商品系统)在同一台服务器上部署,我们希望的日志路径和命名方式是

    /data/logs/order/order-info.log

    /data/logs/order/order-error.log

    /data/logs/goods/goods-info.log

    /data/logs/goods/goods-error.log

    那也就是动态化服务应用名,如上面Property配置有个SERVER_NAME常量,我这里取自System变量,以此作为服务名。下面的appender使用${SERVER_NAME} 相当于获取了动态服务名

    System.setProperty("SERVICE_NAME", "demo");

    log4j2提供了多个Lookups来满足类似的功能,http://logging.apache.org/log4j/2.x/manual/lookups.html

    可以根据实际的项目需求来选择,也可以自定义属于自己的lookup。

    3,4、日志如何滚动,日志过期策略

    我们以上面的log4j-xinclude-appenders.xml配置中的FILE-INFO来解释

    <!--http://logging.apache.org/log4j/2.x/manual/appenders.html#RollingRandomAccessFileAppender-->
        <!--
        name:FILE-INFO  appender 名字可以自定义,logger引用使用
        fileName:当前日志名称,如果是多级目录,则会自动创建
        filePattern:归档日志格式
        -->
        <RollingRandomAccessFile name="FILE-INFO"
                                 fileName="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-info.log"
                                 filePattern="${BASE_LOG_PATH}/${SERVER_NAME}/${SERVER_NAME}-info.%d{yyyy-MM-dd}-%i.log.gz">
            <!--
                minLevel:最小日志级别
                maxLevel:最大日志级别
                onMatch:匹配成功接收
                onMismatch:匹配失败丢弃
            -->
            <LevelRangeFilter minLevel="WARN" maxLevel="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            <!--
                pattern:日志格式
                charset:日志字符编码
            -->
            <PatternLayout pattern="${PATTERN}" charset="${CHARSET}" />
            <Policies>
                <!--每天滚动一次,interval的单位 取决于filePattern 我这里定义的是dd(天)也就是每天会产生一个新的日志文件 -->
                <TimeBasedTriggeringPolicy interval="1"/>
                <!--或者日志文件达到10KB 滚动一次-->
                <SizeBasedTriggeringPolicy size="10KB"/>
            </Policies>
            <!--日志删除策略-->
            <!--DefaultRolloverStrategy 默认的max=7 代表的是dd(天)最多产生7个文件,多余自动删除,但是我们会自己定义删除策略所以要屏蔽这个配置,如果不屏蔽这个配置,则当天日志最多只有7个 -->
            <!--源码:org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy.Builder.build ,当fileIndex=nomax,不在使用max变量 -->
            <DefaultRolloverStrategy fileIndex="nomax">
                <!--basePath:从此处扫描需要删除的日志基本路径,maxDepth:要访问的日志目录最大级别数,默认是1  -->
                <!--例如我们的日志是/data/logs/app/app-info.log,basePath=/data/logs,maxDepth=2 恰好能访问到app-info.log -->
                <Delete basePath="${BASE_LOG_PATH}/${SERVER_NAME}" maxDepth="2">
                    <!--删除,正则匹配到文件名-->
                    <IfFileName glob="*-info.*.log.gz"/>
                    <!--删除,日志距离现在多长事件,P1D代表是1天-->
                    <!--http://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/appender/rolling/action/Duration.html-->
                    <IfLastModified age="P1D"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingRandomAccessFile>

    log4j2提供多种Appender,http://logging.apache.org/log4j/2.x/manual/appenders.html#   ,因为我们是输入到文件里,所以这里讲RollingRandomAccessFile ,为什么选择RollingRandomAccessFile 呢?官方的描述是:http://logging.apache.org/log4j/2.x/manual/appenders.html#RollingRandomAccessFileAppender

    image

    大致意思是,RollingRandomAccessFileAppender和RollingFileAppender 相似,但是它内部是基于ByteBuffer + RandomAccessFile,所以这个性能提高了20-200%,不支持文件锁定,可以自定义文件删除操作等骚操作。

     

    5、异步日志

    主要配置在loggers

    log4j2的异步日志需要借助LMAX Disruptor 官方文档:

    http://logging.apache.org/log4j/2.x/manual/async.html#
     
    <loggers>
        <!--includeLocation 打印行号,如果这里不设置,就算%L 也不会打印行号-->
        <AsyncRoot level="DEBUG" includeLocation="true" >
            <AppenderRef ref="CONSOLE"/>
        </AsyncRoot>
        <AsyncLogger name="com.luna" level="INFO" includeLocation="true" >
            <appender-ref ref="FILE-INFO"/>
            <appender-ref ref="FILE-ERROR"/>
        </AsyncLogger>
        <AsyncLogger name="druid.sql.Statement" level="DEBUG" additivity="false" includeLocation="true" >
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="FILE-INFO"/>
        </AsyncLogger>
    </loggers>

    关于异步日志性能,按照官方文档的说法log4j2是目前最强的!http://logging.apache.org/log4j/2.x/manual/async.html#AllAsync

    参考文献:

    1、http://logging.apache.org/log4j/2.x/

    2、https://www.ralphgoers.com/post/getting-the-most-out-of-the-log4j-2-api

    3、https://my.oschina.net/xianggao/blog/523401

  • 相关阅读:
    poj2955(区间dp)
    poj3280(区间dp)
    poj1651(区间dp)
    hdu5001(概率dp)
    hdu4389(数位dp)
    hdu4352(数位dp)
    CF 148D(概率dp)
    zoj3329(概率dp)
    POJ1028 Web Navigation
    POJ1027 The Same Game
  • 原文地址:https://www.cnblogs.com/gyjx2016/p/13667726.html
Copyright © 2011-2022 走看看