跳到主要內容

Log4j2 - Hello World!

Introduction

本篇文章主要針對Log4j2設定的基本結構做介紹,讓大家可以快速進入Log4j2的世界。Log4j2的configuration file提供了XML、JSON、YAML與properties設定的方式,為了利於Log4j1轉換到Log4j2的格式銜接,我選擇了properties格式做介紹。

Example

一個Log4j2的設定檔,幾乎都會有以下三個元素,包含全域定義、Appender定義與Logger定義。接下來將會針對這三個元素做基本介紹。

# part1  全域定義
status = warn
name= CommonLogSettingForUnitTests
rootLogger = DEBUG, CONSOLE
 
# part2 Appender定義
appender.console.type = Console
appender.console.name = CONSOLE
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{mm:ss,SSS}|%5p[%t] (%F:%M:%L) %m %n
appender.console.filter.threshold.type = ThresholdFilter
appender.console.filter.threshold.level = ALL
 
# part3 Logger定義
logger.reflections = DEBUG, CONSOLE
logger.reflections.name = org.reflections.Reflections
logger.reflections.additivity = false
 
logger.default = DEBUG, CONSOLE
logger.default.name = org.tonylin.practice
logger.default.additivity = false

全域定義

以本篇範例所提及的項目來說:

status = warn
name= CommonLogSettingForUnitTests
rootLogger = DEBUG, CONSOLE

  • status: 設定log4j本身的事件的level,會以console形式輸出。如果你懷疑log4j設定有問題,可以改這個設定成trace或debug去看問題出在哪,也可以透過設定system properties “log4j2.debug=true”去enable所有log內容。
  • name: configuration file所對應的configuration名稱。這個目前看起來有將設定分在多個檔案的情況才比較有用,可以參考XIncludeCompositeConfiguration
  • rootLogger: 等同於log4j1的log4j.rootLogger,沒有設定logger的預設行為。以我的範例來說,就是希望針對DEBUG level以上的所有情況,去使用CONSOLE appender定義的方式做log。如果要串多組appender,就直接加在CONSOLE後,以逗號區隔。

除了我介紹的三個項目以外,目前我有看到的全域定義還有filterproperties,可用於定義預設log過濾規則與變數定義,有興趣的人可以先自行研究,之後文章有用到我再說明。

Appender定義

Appender定義我認為是log4j設定檔中最複雜的一塊,因為這個完全取決於你:log格式為何、要log在哪裡、log保留形式為何等等,這也是安全性最容易出問題的地方。我先針對範例有提及的元素做說明。

appender.console.type = Console
appender.console.name = CONSOLE
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{mm:ss,SSS}|%5p[%t] (%F:%M:%L) %m %n
appender.console.filter.threshold.type = ThresholdFilter
appender.console.filter.threshold.level = ALL

  • appender.console.type: 這個影響的是要log在哪裡與log保留形式,以範例來說是輸出到Conosle上。也有可能會輸出到file、syslog、smtp、database,取決於你的需求而使用不同的appender type。我有使用到的項目會再整理其它文章內容給大家參考。
  • appender.console.name: Appender的名稱,提供給後續Logger定義做參考使用。
  • appender.console.layout: 這個影響的是log格式,可以參考link去設定你想要的樣子。以這個範例來說,輸出會長這樣子: 47:27,691| INFO[main] (ClassName.java:MetohdName:59) hello world!。
  • appender.console.filter: 這是用來設定此appender需要log的條件,以本篇範例來說,因為設定成ALL,代表要log所有內容。

假如我要設定第二組不同的Console設定的話,範例如下,另外只要在Logger設定中指定CONSOLE2即可:

appender.console2.type = Console
appender.console2.name = CONSOLE2
...

Logger定義

這個就是決定了你哪些東西需要做log與對應的appender為何。以本篇範例來說,總共設定了兩組logger(key以reflections與default區分),兩者差別只在於:

  • logger.reflections: 設定套用在org.reflections.Reflections這個class上。
  • logger.default: 設定套用在org.tonylin.practice這個底下所有的packages。

不滿足以上規則的class或package,就會套用在全域定義中rootLogger的方式。接下來針對範例有提及的元素做說明,用reflections這組為例。

logger.reflections = DEBUG, CONSOLE
logger.reflections.name = org.reflections.Reflections
logger.reflections.additivity = false
 
logger.default = DEBUG, CONSOLE
logger.default.name = org.tonylin.practice
logger.default.additivity = false

  • logger.reflections: 定義log的方式,與rootLogger定義方式相同。
  • logger.reflections.name: 定義logger所對應的package或class。
  • logger.reflections.additivity: 目前我還摸不清它的訊息附加的規則是怎樣執行的,假如你有發現訊息重複log的情況,不妨把它設成false看看。

註: 如果全域定義中有設定ThresholdFilter與對應的level,要注意會以全域定義的為主。

Reference

留言

這個網誌中的熱門文章

解決RobotFramework從3.1.2升級到3.2.2之後,Choose File突然會整個Hand住的問題

考慮到自動測試環境的維護,我們很久以前就使用java去執行robot framework。前陣子開始處理從3.1.2升級到3.2.2的事情,主要先把明確的runtime語法錯誤與deprecate item處理好,這部分內容可以參考: link 。 直到最近才發現,透過SeleniumLibrary執行Choose File去上傳檔案的動作,會導致測試案例timeout。本篇文章主要分享心路歷程與解決方法,我也送了一條issue給robot framework: link 。 我的環境如下: RobotFramework: 3.2.2 Selenium: 3.141.0 SeleniumLibrary: 3.3.1 Remote Selenium Version: selenium-server-standalone-3.141.59 首先並非所有Choose File的動作都會hang住,有些測試案例是可以執行的,但是上傳一個作業系統ISO檔案一定會發生問題。後來我透過wireshark去比對新舊版本的上傳動作,因為我使用 Remote Selenium ,所以Selenium會先把檔案透過REST API發送到Remote Selenium Server上。從下圖我們可以發現,在3.2.2的最後一個TCP封包,比3.1.2大概少了500個bytes。 於是就開始了我trace code之路。包含SeleniumLibrary產生要送給Remote Selenium Server的request內容,還有HTTP Content-Length的計算,我都確認過沒有問題。 最後發現問題是出在socket API的使用上,就是下圖的這支code: 最後發現可能因為開始使用nio的方式送資料,但沒處理到尚未送完的資料內容,而導致發生問題。加一個loop去做計算就可以解決了。 最後我有把解法提供給robot framework官方,在他們出新的版本之前,我是將改完的_socket.py放在我們自己的Lib底下,好讓我們測試可以正常進行。(shutil.py應該也是為了解某個bug而產生的樣子..)

Show NIC selection when setting the network command with the device option

 Problem  在answer file中設定網卡名稱後,安裝時會停在以下畫面: 所使用的command參數如下: network --onboot = yes --bootproto =dhcp --ipv6 =auto --device =eth1 Diagnostic Result 這樣的參數,以前試驗過是可以安裝完成的。因此在發生這個問題後,我檢查了它的debug console: 從console得知,eth1可能是沒有連接網路線或者是網路太慢而導致的問題。後來和Ivy再三確認,有問題的是有接網路線的網卡,且問題是發生在activate階段: Solution 我想既然有retry應該就有次數或者timeout限制,因此發現在Anaconda的說明文件中( link ),有提到dhcptimeout這個boot參數。看了一些人的使用範例,應該是可以直接串在isolinux.cfg中,如下: default linux ksdevice = link ip =dhcp ks =cdrom: / ks.cfg dhcptimeout = 90 然而我在RHEL/CentOS 6.7與6.8試驗後都無效。 因此我就拿了顯示的錯誤字串,問問Google大師,想找一下Anaconda source code來看一下。最後找到別人根據Anaconda code修改的版本: link ,關鍵在於setupIfaceStruct函式中的setupIfaceStruct與readNetConfig: setupIfaceStruct: 會在dhcp時設定dhcptimeout。 readNetConfig: 在writeEnabledNetInfo將timeout寫入dhclient config中;在wait_for_iface_activation內會根據timeout做retry。 再來從log與code可以得知,它讀取的檔案是answer file而不是boot command line。因此我接下來的測試,就是在answer file的network command上加入dhcptimeout: network --onboot = yes --bootproto =dhcp --ipv6 =auto --device =eth1 --...

Robot Framework - Evaluate該怎麼用?

Evaluate該怎麼用? 前言 Builtin的RobotFramework Library提供了Evaluate Keyword。它所提供的功能是「執行Python描述句」。但實際上到底有什麼用途呢?原本我僅僅拿來將string轉為int的功用,經過一些查詢與試驗,我將心得整理給大家。 Builtin Builtin的function可以參考Library Doc for Evaluate。我以有使用過的function做說明。 數字轉換 Python提供了int、long、float與complex等function讓你可以將字串轉為數字,也可以透過它們做四則運算。首先以字串轉數字為例,我將8設於${num_str}中,再透過Evaluate+int轉為數字。這裡必須注意的是: 「int()中放變數必須以單引號'括起」。否則,假如你設定的數字為08,在轉換int時會出現Syntax Error。 ${num_str} | Set Variable | 8 ${num} | Evaluate | int('${num_str}') 其中int與long的第二個參數為base,這是根據你的input所決定: Comment | num = 9 ${num} | Evaluate | int('11', 8) Comment | num = 11 ${num} | Evaluate | int('11', 10) Comment | num = 17 ${num} | Evaluate | int('11', 16) 其它還有像bin、oct、hex,可以將整數轉為2、8、16進位。 運算 四則運算: 直接將運算子加上即可: ${num} | Evaluate | int('${hour}')*60 + int('${min}') 指數: 可以用pow。以下面兩個例子來說,第一個是2的3次方為8,第二個是2的3次方再mod 7為1。需注意的是: 「傳入值必須是數字不可為字串」。 ${num} | Evaluate | pow(2,3) ${num} | Evaluate | pow(2,3,7) 取最大最小值: 使用max/min,可以選擇丟一個array的方式...