【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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM