Log4j 2使用教程二 【详解】
配置
Log4j 2的配置可以通過4種方式中的1種完成:
1、通過使用XML,JSON,YAML或屬性格式編寫的配置文件。 2、以編程方式,通過創建一個ConfigurationFactory和配置實現。 3、以編程方式,通過調用配置界面中公開的API將組件添加到默認配置。 4、通過編程方式,通過調用內部Logger類的方法。我主要是講解配置文件的方式?
編程的方式可以參考:?Extending Log4j 2和Programmatic Log4j Configuration.
自動配置
Log4j能夠在初始化期間自動配置自身。?
當Log4j啟動時,將找到所有ConfigurationFactory插件,并按照從最高到最低的加權順序進行排列。?
交付時,Log4j包含四個ConfigurationFactory實現:一個用于JSON,一個用于YAML,一個用于properties,一個用于XML。
1、Log4j將檢查log4j.configurationFile系統屬性,如果設置,將嘗試使用與文件擴展名匹配的ConfigurationFactory加載配置。?
2、如果沒有設置系統屬性,則properties ConfigurationFactory將在類路徑中查找log4j2-test.properties。?
3、如果沒有找到這樣的文件,YAML ConfigurationFactory將在類路徑中查找log4j2-test.yaml或log4j2-test.yml。?
4、如果沒有找到這樣的文件,JSON ConfigurationFactory將在類路徑中查找log4j2-test.json或log4j2-test.jsn。?
5、如果沒有找到這樣的文件,XML ConfigurationFactory將在類路徑中查找log4j2-test.xml。?
6、如果找不到測試文件,則properties ConfigurationFactory將在類路徑中查找log4j2.properties。?
7、如果無法找到屬性文件,則YAML ConfigurationFactory將在類路徑上查找log4j2.yaml或log4j2.yml。?
8、如果無法找到YAML文件,則JSON ConfigurationFactory將在類路徑上查找log4j2.json或log4j2.jsn。?
9、如果無法找到JSON文件,則XML ConfigurationFactory將嘗試在類路徑上找到log4j2.xml。?
10、如果沒有找到配置文件,將使用DefaultConfiguration。這將導致日志輸出轉到控制臺。
日志級別
log4j規定了默認的幾個級別:trace<debug<info<warn<error<fatal等。這里要說明一下:
①級別之間是包含的關系,意思是如果你設置日志級別是trace,則大于等于這個級別的日志都會輸出。?
②基本上默認的級別沒多大區別,就是一個默認的設定。你可以通過它的API自己定義級別。你也可以隨意調用這些方法,不過你要在配置文件里面好好處理了,否則就起不到日志的作用了,而且也不易讀,相當于一個規范,你要完全定義一套也可以,不用沒多大必要。?
③這不同的級別的含義大家都很容易理解,這里就簡單介紹一下:
| trace | 是追蹤,就是程序推進以下,你就可以寫個trace輸出,所以trace應該會特別多,不過沒關系,我們可以設置最低日志級別不讓他輸出。 |
| debug | 調試么,我一般就只用這個作為最低級別,trace壓根不用。是在沒辦法就用eclipse或者idea的debug功能就好了么。 |
| info | 輸出一下你感興趣的或者重要的信息,這個用的最多了。 |
| warn | 有些信息不是錯誤信息,但是也要給程序員的一些提示,類似于eclipse中代碼的驗證不是有error 和warn(不算錯誤但是也請注意,比如以下depressed的方法)。 |
| error | 錯誤信息。用的也比較多。 |
| fatal | 級別比較高了。重大錯誤,這種級別你可以直接停止程序了,是不應該出現的錯誤么!不用那么緊張,其實就是一個程度的問題。 |
日志使用
緊接上篇博文
例子1:
<?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的,所以會被打印兩遍。--><logger name="cn.lsw.base.log4j2.Hello" level="trace" additivity="false"><appender-ref ref="Console"/></logger><root level="error"><appender-ref ref="Console"/></root></loggers> </configuration>先簡單介紹一下下面這個配置文件。?
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(名稱)了(前面有提到)。
name機制
可以參考:?http://logging.apache.org/log4j/2.x/manual/architecture.html
我們看到配置文件中的那個name是非常重要的。這個name要用好的,就不能隨便亂起。?
(隨便用的話,那就隨便取名字)。這個機制很簡單,就類似于java package一樣。?
上篇中創建logger對象的時候,名稱是通過Hello.class或者Hello.class.getName()這樣的方法。為什么要這樣做呢?很重要的原因就是有所謂的繼承問題。比如 如果你給com.Hello定義了一個logger,那么它也適用于com.Hello.base這個logger。名稱的繼承是通過(.)點號分隔的。然后你會返現上面的loggers里面有個子節點不是logger而是root,而且這個root沒有name屬性。?
這個root相當于根節點。你所有的logger都適用于這個logger,所以,即使你在很多類里面通過類名.class.getName()或者類名.class得到很多的logger,而且你也沒有在配置文件中進行任何配置,它們也能夠都輸出,因為他們都繼承了root的log配置。
這種繼承的說法官網的解釋叫做logger 層次結構(Hierarchy)?
官網的例子:
上面的那個配置文件里面還定義了一個logger,他的名稱是cn.lsw.base.log4j2.Hello,這個名稱其實就是通過前面的Hello.class.getName()或者Hello.class得到的。上面那個配置文件,我們為了給它做單獨配置。意思是:只有cn.lsw.base.log4j2.Hello這個logger輸出trace信息。也就是它的日志級別為trace,其他的logger則繼承root的日志配置,日志級別為error,只能打印出error及以上級別的日志。
那么有人會問,你單獨配置的那個logger不也是繼承了root的配置么,那這樣的話,豈不是會打印兩遍日志? 這個問題確實是存在的。當然如果你設置了additivity=false,就不會輸出兩遍。
我們再寫一個測試類:?
(我們先對上面的配置文件做下修改,一個是logger的name改為:test.Hello,第二把additivity=false去掉或改為true)
結果就是:
2017-05-17 11:51:40.783 [main] TRACE test.Hello - Enter 2017-05-17 11:51:40.783 [main] TRACE test.Hello - Enter 2017-05-17 11:51:40.787 [main] TRACE test.Hello - 我是trace 2017-05-17 11:51:40.787 [main] TRACE test.Hello - 我是trace 2017-05-17 11:51:40.787 [main] INFO test.Hello - 我是info信息 2017-05-17 11:51:40.787 [main] INFO test.Hello - 我是info信息 2017-05-17 11:51:40.787 [main] ERROR test.Hello - 我是error 2017-05-17 11:51:40.787 [main] ERROR test.Hello - 我是error 2017-05-17 11:51:40.787 [main] FATAL test.Hello - 我是fatal 2017-05-17 11:51:40.787 [main] FATAL test.Hello - 我是fatal 2017-05-17 11:51:40.787 [main] TRACE test.Hello - 退出程序. 2017-05-17 11:51:40.787 [main] TRACE test.Hello - 退出程序. 2017-05-17 11:51:40.787 [main] TRACE test.Hello - Exit 2017-05-17 11:51:40.787 [main] TRACE test.Hello - Exit我們可以看出主程序Logger2Test并沒有trace日志輸出,因為它繼承了root的日志配置(error級別及以上)。而Hello輸出了trace及以上級別的日志,但是呢,每個都輸出了兩遍。為什么會這樣呢?前面也說過默認所有的logger都繼承root的配置的。此時的Hello既有自己單獨的配置,也有從root那里繼承下來的配置,所以會打印兩次。這樣的特性,在其name的層次結構中也是同樣適用的,比如:
我創建三個logger名稱為test、test.Hello和test.Hello.Hello2
<?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 name="test.Hello" level="info" additivity="true"><appender-ref ref="Console"/></logger><logger name="test.Hello" level="info" additivity="true"><appender-ref ref="Console"/></logger><logger name="test.foo.Hello2" level="info" additivity="true"><appender-ref ref="Console"/></logger><root level="error"><appender-ref ref="Console" /></root></loggers> </configuration>打印結果:
2017-05-17 14:18:09.388 [main] INFO test.Hello - 我是info信息 2017-05-17 14:18:09.388 [main] INFO test.Hello - 我是info信息 2017-05-17 14:18:09.388 [main] INFO test.Hello - 我是info信息 2017-05-17 14:18:09.392 [main] ERROR test.Hello - 我是error 2017-05-17 14:18:09.392 [main] ERROR test.Hello - 我是error 2017-05-17 14:18:09.392 [main] ERROR test.Hello - 我是error 2017-05-17 14:18:09.392 [main] FATAL test.Hello - 我是fatal 2017-05-17 14:18:09.392 [main] FATAL test.Hello - 我是fatal 2017-05-17 14:18:09.392 [main] FATAL test.Hello - 我是fatal 2017-05-17 14:18:09.393 [main] INFO test.foo.Hello2 - 我是info信息 2017-05-17 14:18:09.393 [main] INFO test.foo.Hello2 - 我是info信息 2017-05-17 14:18:09.393 [main] INFO test.foo.Hello2 - 我是info信息 2017-05-17 14:18:09.393 [main] ERROR test.foo.Hello2 - 我是error 2017-05-17 14:18:09.393 [main] ERROR test.foo.Hello2 - 我是error 2017-05-17 14:18:09.393 [main] ERROR test.foo.Hello2 - 我是error 2017-05-17 14:18:09.393 [main] FATAL test.foo.Hello2 - 我是fatal 2017-05-17 14:18:09.393 [main] FATAL test.foo.Hello2 - 我是fatal 2017-05-17 14:18:09.393 [main] FATAL test.foo.Hello2 - 我是fatal可以看出打印三篇。
在實際使用過程中,我們其實就是需要一個就行了,這時你可以設置:additivity=false。?
它會把父類全部屏蔽掉。官方說法就是把追加性關閉。
現在我們看一個稍微復雜的例子:
<?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>轉載于:https://www.cnblogs.com/Remenber-Ray/p/8858033.html
總結
以上是生活随笔為你收集整理的Log4j 2使用教程二 【详解】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 明基投影仪怎么连接笔记本电脑(明基投影仪
- 下一篇: hadoop hdfs (java ap