1. 程式人生 > >log4j2實戰--將MyBatis執行SQL記錄到檔案,按天分存

log4j2實戰--將MyBatis執行SQL記錄到檔案,按天分存

需求:將Mybatis的執行SQL,按天存日誌檔案。專案使用的是log4j2。

原先專案,都是將所有日誌通通列印到控制檯。現在需要將系統接收使用者請求後,Mybatis的執行SQL,按天存日誌檔案。

當時在想:
把Mybatis的SQL列印到控制檯容易實現,
日誌按Level級別 按天存檔案也容易實現,
但如何單獨把Mybatis的SQL,按天存日誌檔案呢?

Mybatis 的內建日誌工廠提供日誌功能,內建日誌工廠將日誌交給以下其中一種工具作代理:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK logging

MyBatis 內建日誌工廠基於執行時自省機制選擇合適的日誌工具。它會使用第一個查詢得到的工具(按上文列舉的順序查詢)。如果一個都未找到,日誌功能就會被禁用。

可以在mybatis-config.xml 中,設定使用的日誌元件。

<configuration>
  <settings>
    ...
    <setting name="logImpl" value="LOG4J2"/>
    ...
  </settings>
</configuration>

logImpl 可選的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING,或者是實現了介面org.apache.ibatis.logging.Log

 的,且構造方法是以字串為引數的類的完全限定名。



通過學習發現:Mybatis 中 SQL 語句的日誌級別被設為DEBUG(JDK 日誌設為 FINE),SQL執行結果的日誌級別為 TRACE(JDK 日誌設為 FINER)。

所以,如果某些查詢可能會返回龐大的結果集,此時只想記錄其執行的 SQL 語句而不想記錄結果該怎麼辦,只要將日誌級別調整為 DEBUG 即可達到目的。

可見:無論使用哪個日誌元件、無論列印什麼內容,均是按日誌級別進行輸出的。所以在本需求中,Mybatis的SQL按debug級別輸出到指定地方即可。

無論是Mybatis框架,還是Spring、Java Mail框架,如果想看到框架底層執行的日誌資訊,配置日誌級別為debug即可。

再次說明下,Mybatis 內建日誌工廠將日誌交給其中一種日誌工具作代理。具體怎麼做,由使用的日誌工具決定,因此本需求MyBatis執行SQL的檔案儲存,是取決於使用的log4j2日誌元件實現。

下面就來看一下log4j2具體的配置。

在log4j2中, 共有8個輸出級別,按照從低到高為:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF。

log4j2 的配置檔案支援 xml、json、jsn 三種格式,預設情況下由系統自動載入,其要在classpath 可載入到的目錄下。

日誌配置檔案主要配置2大類
1、配置輸出源<Appenders>:日誌輸出到哪裡。如控制檯、file等
2、具體的日誌配置<Loggers>:配置name,啟用哪個Appender,以及日誌級別等。

下面給出本需求的簡單配置實現:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR" monitorInterval="600">
    <!-- configure.status 為設定日誌輸出級別,級別如下:OFF 、FATAL 、ERROR、WARN、INFO、DEBUG、TRACE、ALL -->
    <!-- configure.monitorInterval 監控間隔 指log4j2每隔600秒(10分鐘),自動監控該配置檔案是否有變化,如果變化,則自動根據檔案內容重新配置 -->

    <Properties>
        <property name="pattern">%d{yyyy/MM/dd HH:mm:ss.SSS} [%p] %t %c %m%n</property>
        <property name="basePath">/Users/lijianhua/Documents/my-log</property>
    </Properties>

    <!--配置appenders源:日誌輸出的地址-->
    <Appenders>

        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="${pattern}"/>
        </Console>

        <RollingRandomAccessFile name="fileLogger"
                                 fileName="${basePath}/mybatis-sql.log"
                                 filePattern="${basePath}/mybatis-sql-%d{yyyy-MM-dd}.log"
                                 append="true">
            <PatternLayout pattern="${pattern}"/>

            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <SizeBasedTriggeringPolicy size="100MB"/>
            </Policies>
        </RollingRandomAccessFile>
    </Appenders>

    <!--配置logers:級別、使用的輸出地-->
    <Loggers>
        <Logger name="com.ljheee.app.dao" level="debug" additivity="true">
            <appender-ref ref="fileLogger" level="debug"/>
        </Logger>

        <Root level="info" additivity="false">
            <appender-ref ref="console"/>
        </Root>
    </Loggers>
</Configuration>

通常log4j 採用properties檔案配置。log4j2 採用xml檔案配置。

log4j2 的xml檔案配置,根節點是<Configuration>,它有2個可選屬性:

  • status 為設定日誌輸出級別,級別如下:OFF 、FATAL 、ERROR、WARN、INFO、DEBUG、TRACE 、ALL
  • monitorInterval 監控間隔 指log4j2每隔600秒(10分鐘),自動監控該配置檔案是否有變化,如果變化,則自動根據檔案內容重新配置。

1、配置輸出源<Appenders>:

配置日誌輸出到哪裡。如控制檯、file等。

<Appenders>下通常有一個<Console> 表示日誌都輸出到控制檯,方便開發期間進行檢視。

另一個是<RollingRandomAccessFile>,按時間和檔案大小滾動(rollover)的RollingRandomAccessFile Appender,名字真是夠長,但不光只是名字長,相比RollingFileAppender有很大的效能提升,官網宣稱是20-200%。

rollover的意思是當滿足一定條件(如檔案達到了指定的大小,達到了指定的時間)後,就重新命名原日誌檔案進行歸檔,並生成新的日誌檔案用於log寫入。如果還設定了一定時間內允許歸檔的日誌檔案的最大數量,將對過舊的日誌檔案進行刪除操作。

這裡說的“滿足一定條件”,是需要觸發的,需要配置基於時間的、或基於日誌檔案大小的觸發策略,也就是如下配置:

            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <SizeBasedTriggeringPolicy size="100MB"/>
            </Policies>

關鍵點在於 filePattern後的日期格式,以及TimeBasedTriggeringPolicy的interval,日期格式精確到哪一位,interval也精確到哪一個單位。在本示例中,filePattern最小單位是天,interval=1也就是一天一個日誌檔案。

TimeBasedTriggeringPolicy基於時間的觸發策略

屬性 解釋
interval (integer)該屬性是相對 RollingFile.filePattern 中的 %d{yyyy-MM-dd}值,例:filePattern=”xxx%d{yyyy-MM-dd}xx” interval=”2” 表示將2天一個日誌檔案;filePattern=”xxx%d{yyyy-MM-dd-HH}xx” interval=”1”表示一個小時一個日誌檔案
modulate (boolean)以0點為邊界進行偏移計算

2、具體的日誌配置<Loggers>:

配置name,啟用哪個Appender,以及日誌級別等。

重點說明

<Logger name="com.ljheee.app.dao" level="debug" additivity="true">
            <appender-ref ref="fileLogger" level="debug"/>
</Logger>

MyBatis支援多種粒度的日誌記錄:

1、可以記錄某個對映器介面的日誌
將name設為name="com.ljheee.app.dao.UserMapper"
就會記錄 com.ljheee.app.dao.UserMapper 的詳細執行操作,且僅記錄應用中其它類的錯誤資訊(若有)。

2、還可以將日誌的記錄方式從介面級別切換到語句級別,從而實現更細粒度的控制。如下配置只對 select 語句記錄日誌:
將name設為name="com.ljheee.app.dao.UserMapper.select"

3、當然也可以按例項配置到包級別,在DAO層,將包下所有MyBatis的mapper介面均使用日誌記錄。

小結:

log4j2 是Apache開發的一款log4j的升級產品,在某些特定的場景上面,甚至可以比之前的速度快上10倍。在保證log的元件更加快速的同時,同時所需的記憶體更加少。

上面在說RollingRandomAccessFile時,也說到效能很高,因為log4j2 內部使用了Disruptor高效能併發框架,輸出日誌採用非同步輸出,極高地提升了日誌輸出效能,因此也建議將後續的應用日誌方式,切換到log4j2。