1. 程式人生 > 其它 >《手把手教你》系列基礎篇(八十八)-java+ selenium自動化測試-框架設計基礎-Log4j 2實現日誌輸出-下篇(詳解教程)

《手把手教你》系列基礎篇(八十八)-java+ selenium自動化測試-框架設計基礎-Log4j 2實現日誌輸出-下篇(詳解教程)

1.簡介

上一篇巨集哥講解和分享瞭如何在控制檯輸出日誌,但是你還需要複製貼上才能發給相關人員,而且由於介面大小限制,你只能獲取當前的日誌,因此最好還是將日誌適時地記錄在檔案中直接打包發給相關人員即可。因此這一篇巨集哥主要講解和分享如何通過log4j2將日誌輸出到檔案中。

2.配置檔案

先簡單介紹一下下面這個配置檔案。

1)根節點configuration,然後有兩個子節點:appenders和loggers(都是複數,意思就是可以定義很多個appender和logger了)(如果想詳細的看一下這個xml的結構,可以去jar包下面去找xsd檔案和dtd檔案)

2)appenders:這個下面定義的是各個appender,就是輸出了,有好多類別,這裡也不多說(容易造成理解和解釋上的壓力,一開始也未必能聽懂,等於白講),先看這個例子,只有一個Console,這些節點可不是隨便命名的,Console就是輸出控制檯的意思。然後就針對這個輸出設定一些屬性,這裡設定了PatternLayout就是輸出格式了,基本上是前面時間,執行緒,級別,logger名稱,log資訊等,差不多,可以自己去查他們的語法規則。

3)loggers下面會定義許多個logger,這些logger通過name進行區分,來對不同的logger配置不同的輸出,方法是通過引用上面定義的logger,注意,appender-ref引用的值是上面每個appender的name,而不是節點名稱。

這個例子為了說明什麼呢?巨集哥要說說這個logger的name(名稱)了(上一篇文章 開頭部分有提到)。

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
    <appenders>
        <Console 
name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </appenders> <loggers> <!--我們只讓這個logger輸出trace資訊,其他的都是error級別--> <!-- additivity開啟的話,由於這個logger也是滿足root的,所以會被列印兩遍。 不過root logger 的level是error,為什麼Bar 裡面的trace資訊也被列印兩遍呢
--> <logger name="testSuites.Test" level="trace" additivity="false"> <appender-ref ref="Console"/> </logger> <root level="error"> <appender-ref ref="Console"/> </root> </loggers> </configuration>

3.name的機制

想要詳細瞭解的同學們或者小夥伴們可以參考: http://logging.apache.org/log4j/2.x/manual/architecture.html)

我們這裡看到了配置檔案裡面是name很重要,沒錯,這個name可不能隨便起(其實可以隨便起)。這個機制意思很簡單。就是類似於java package一樣,比如我們的一個包:cn.lsw.base.log4j2。而且,可以發現我們前面生成Logger物件的時候,命名都是通過 Hello.class.getName(); 這樣的方法,為什麼要這樣呢? 很簡單,因為有所謂的Logger 繼承的問題。比如 如果你給cn.lsw.base定義了一個logger,那麼他也適用於cn.lsw.base.lgo4j2這個logger。名稱的繼承是通過點(.)分隔的。然後你可以猜測上面loggers裡面有一個子節點不是logger而是root,而且這個root沒有name屬性。這個root相當於根節點。你所有的logger都適用與這個logger,所以,即使你在很多類裡面通過 類名.class.getName() 得到很多的logger,而且沒有在配置檔案的loggers下面做配置,他們也都能夠輸出,因為他們都繼承了root的log配置。

我們上面的這個配置檔案裡面還定義了一個logger,他的名稱是 testSuites.Test ,這個名稱其實就是通過前面的Hello.class.getName(); 得到的,我們為了給他單獨做配置,這裡就生成對於這個類的logger,上面的配置基本的意思是隻有testSuites.Test 這個logger輸出trace資訊,也就是他的日誌級別是trace,其他的logger則繼承root的日誌配置,日誌級別是error,只能打印出ERROR及以上級別的日誌。如果這裡logger 的name屬性改成cn.lsw.base,則這個包下面的所有logger都會繼承這個log配置(這裡的包是log4j的logger name的“包”的含義,不是java的包,你非要給Hello生成一個名稱為“myhello”的logger,他也就沒法繼承cn.lsw.base這個配置了。

那有人就要問了,他不是也應該繼承了root的配置了麼,那麼會不會輸出兩遍呢?我們在配置檔案中給瞭解釋,如果你設定了additivity="false",就不會輸出兩遍,否則,看下面的輸出:

1.這裡要在加入一個類做對比,如下圖所示: 

 2.這裡先把配置檔案改一下方便對照,一個是剛才第一個logger的名稱還是testSuites.Test,additivity去掉或改為true(因為預設是true,所以可以去掉),第二是把root的level改為info方便觀察。 然後執行Test,看控制檯的日誌輸出:

可以看出,Test的trace日誌沒有輸出,因為他繼承了root的日誌配置,只輸出info即以上級別的日誌。Hello 輸出了trace及以上級別的日誌,但是每個都輸出了兩遍。你可以試一下,把第一個logger的level該為error,那麼error以上的級別也是輸出兩遍。這時候,只要加上additivity為false就可以避免這個問題了。

當然,你可以為每個logger 都在配置檔案下面做不同的配置,也可以通過繼承機制,對不同包下面的日誌做不同的配置。因為loggers下面可以寫很多個logger。

4.複雜的配置檔案

<?xml version="1.0" encoding="UTF-8"?>

<configuration status="error">
    <!--先定義所有的appender-->
    <appenders>
        <!--這個輸出控制檯的配置-->
        <Console name="Console" target="SYSTEM_OUT">
            <!--控制檯只輸出level及以上級別的資訊(onMatch),其他的直接拒絕(onMismatch)-->
            <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>
            <!--這個都知道是輸出日誌的格式-->
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </Console>
        <!--檔案會打印出所有資訊,這個log每次執行程式會自動清空,由append屬性決定,這個也挺有用的,適合臨時測試用-->
        <File name="log" fileName="log/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </File>

        <!--這個會打印出所有的資訊,每次大小超過size,則這size大小的日誌會自動存入按年份-月份建立的資料夾下面並進行壓縮,作為存檔-->
        <RollingFile name="RollingFile" fileName="logs/app.log"
                     filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
            <SizeBasedTriggeringPolicy size="50MB"/>
        </RollingFile>
    </appenders>
    <!--然後定義logger,只有定義了logger並引入的appender,appender才會生效-->
    <loggers>
        <!--建立一個預設的root的logger-->
        <root level="trace">
            <appender-ref ref="RollingFile"/>
            <appender-ref ref="Console"/>
        </root>

    </loggers>
</configuration>

說複雜,其實也不復雜,這一個例子主要是為了講一下appenders。

  這裡定義了三個appender,Console,File,RollingFile,看意思基本也明白,第二個是寫入檔案,第三個是“迴圈”的日誌檔案,意思是日誌檔案大於閥值的時候,就開始寫一個新的日誌檔案。

  這裡我們的配置檔案裡面的註釋算比較詳細的了。所以就大家自己看了。有一個比較有意思的是ThresholdFilter ,一個過濾器,其實每個appender可以定義很多個filter,這個功能很有用。如果你要選擇控制檯只能輸出ERROR以上的類別,你就用ThresholdFilter,把level設定成ERROR,onMatch="ACCEPT" onMismatch="DENY" 的意思是匹配就接受,否則直接拒絕,當然有其他選擇了,比如交給其他的過濾器去處理了之類的,詳情大家自己去琢磨吧。

  為什麼要加一個這樣的配置檔案呢?其實這個配置檔案我感覺挺好的,他的實用性就在下面:

4.1實用性

我們用日誌一方面是為了記錄程式執行的資訊,在出錯的時候排查之類的,有時候除錯的時候也喜歡用日誌。所以,日誌如果記錄的很亂的話,看起來也不方便。所以我可能有下面一些需求:

1)我正在除錯某個類,所以,我不想讓其他的類或者包的日誌輸出,否則會很多內容,所以,你可以修改上面root的級別為最高(或者謹慎起見就用ERROR),然後,加一個針對該類的logger配置,比如第一個配置檔案中的設定,把他的level設定trace或者debug之類的,然後我們給一個appender-ref是定義的File那個appender(共三個appender,還記得嗎),這個appender的好處是有一個append為false的屬性,這樣,每次執行都會清空上次的日誌,這樣就不會因為一直在除錯而增加這個檔案的內容,查起來也方便,這個和輸出到控制檯就一個效果了。

2)我已經基本上部署好程式了,然後我要長時間運行了。我需要記錄下面幾種日誌,第一,控制檯輸出所有的error級別以上的資訊。第二,我要有一個檔案輸出是所有的debug或者info以上的資訊,類似做程式記錄什麼的。第三,我要單獨為ERROR以上的資訊輸出到單獨的檔案,如果出了錯,只查這個配置檔案就好了,不會去處理太多的日誌,看起來頭都大了。怎麼做呢,很簡單。

首先,在appenders下面加一個Console型別的appender,通過加一個ThresholdFilter設定level為error。(直接在配置檔案的Console這個appender中修改)

其次,增加一個File型別的appender(也可以是RollingFile或者其他檔案輸出型別),然後通過設定ThresholdFilter的level為error,設定成File好在,你的error日誌應該不會那麼多,不需要有多個error級別日誌檔案的存在,否則你的程式基本上可以重寫了。

這裡可以新增一個appender,內容如下:

<File name="ERROR" fileName="logs/error.log">
    <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
    <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>

並在loggers中的某個logger(如root)中引用(root節點加入這一行作為子節點)。

<appender-ref ref="ERROR" />

然後,增加一個RollingFile的appender,設定基本上同上面的那個配置檔案。

最後,在logger中進行相應的配置。不過如果你的logger中也有日誌級別的配置,如果級別都在error以上,你的appender裡面也就不會輸出error一下的資訊了。

還記得上面的Test類裡面有一個被註釋掉的for迴圈麼?這個是為了做配置檔案中RollingFile那個appender的配置的,取消註釋,執行商一次或幾次,看你的輸出配置檔案的地方,他是怎麼“RollingFile”的,這裡給個我測試的截圖:(這裡你可以把 <SizeBasedTriggeringPolicy size="50MB"/>這裡的size改成2MB,要生成50MB的日誌還是比較慢的。為了方便觀察麼!然後把Console的ThresholdFilter的level設定成error這樣的較高級別,不然控制檯輸出東西太多了)

 從上圖可以看出:

第一部分是File這個appender生成的日誌檔案,你會發現你執行很多次,這個檔案中的日誌是被覆蓋的。

第二部分是RollingFile 這個appender生成的配置檔案,可以發現,預設建立的是app.log這個日誌,每次超過2MB的時候,就會生成對應年-月的資料夾,和制定命名格式的log檔案,而且是壓縮成gz格式檔案,開啟資源管理器發現這個檔案只有11KB,解壓後就是2MB。

5.小結

  好了,時間也不早了,今天就分享和講解到這裡,希望對您有所幫助,感謝您耐心地閱讀!