在正式使用和配置logback之前,先來了解一下logback中的三個核心組件,日后的使用,我們配置的也是這三類核心組件,所以有必要先對它們有個基礎了解,
1. 日志記錄器(Logger)
Logger
Logger是一個命名物體,并遵循分層命名規則,它的層次由命名中的.符號表示,例如一個logger名為:com.foo,它就是com.foo.bar的父logger,二者有繼承關系,
RootLogger
RootLogger是一個特殊的logger物體,它由logback自身提供,無需我們定義,同時它也是logger繼承結構中的頂級父物件(類似于Java中的Object),所有未定義層級
關系的logger默認都是RootLogger的子集,
Logger的繼承關系
如果一個給定的Logger未指定級別,那么它將從具有明確級別的最近的父類中繼承到父類的日志級別,上邊說了,RootLogger是這個級別中頂級的存在,
如果給定的Logger沒有其他父級,那么最終將繼承RootLogger的日志級別,默認為:DEBUG
| Logger名稱 | 指定的級別 | 有效級別 |
| root | DEBUG | DEBUG |
| X | none | DEBUG |
| X.Y | none | DEBUG |
| X.Y.Z | none | DEBUG |
在這個表中root代表RootLogger,它的默認級別是DEBUG,剩下三行的X X.Y X.Y.Z均未明確指定級別,根據繼承關系,它們的有效級別都為DEBUG,由RootLogger繼承而來
| Logger名稱 | 指定的級別 | 有效級別 |
| root | DEBUG | DEBUG |
| X | INFO | INFO |
| X.Y | none | INFO |
| X.Y.Z | none | INFO |
在這個表格中,X指定了為INFO級別,而X.Y和X.Y.Z均未指定級別,但是它們的有效級別為INFO,是因為距離它們最近的父級X指定了級別為INFO,所以它們繼承了離它們最近的父級日志的級別,
通過上述兩個表格可以明白logger日志等級的繼承關系,下邊來說一下當使用logger.xxx()方法列印日志時的輸出有效規則,所謂的輸出有效規則就是對應級別的日志是否會輸出,
Logger列印輸出規則
按照日志級別由低到高有五個級別,依次為:TRACE, DEBUG, INFO, WARN, ERROR,對應的Logger物體中有五個列印方法:trace, debug, info, warn, error
我們要列印info級別的日志,需要使用logger.info()方法,但是日志是否輸出有其自身的規則,在這里我們將Logger物件的五個級別設為q,而對應的五個列印方法的級別設為p,則有如下規則:
| 列印方法(p) | Logger級別(q) | ||||
| TRACE | DEBUG | INFO | WARN | ERROR | |
| trace | YES | NO | NO | NO | NO |
| debug | YES | YES | NO | NO | NO |
| info | YES | YES | YES | NO | NO |
| warn | YES | YES | YES | YES | NO |
| error | YES | YES | YES | YES | YES |
上述表格用一句話總結:列印方法的級別(p)必須>=Logger的級別(q),如果Logger的級別為info,那么debug和trace方法都不會輸出,因為這兩個級別低于info,不滿足p >= q的條件
關于logger的繼承關系和列印級別的輸出,我寫了一個簡單的demo做為上述表格的演示,代碼如下:
import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import org.slf4j.LoggerFactory; public class SimpleLogLevel { //注意此處的logger物件為:ch.qos.logback.classic.Logger,為了下邊設定日志級別 private static Logger loggerX = (Logger) LoggerFactory.getLogger("X"); private static Logger loggerXY = (Logger) LoggerFactory.getLogger("X.Y"); public static void main(String[] args) { //loggerX未設定日志級別,因此從RootLogger繼承到默認的DEBUG級別 //trace日志不會輸出,因為loggerX級別為debug,只會輸出級別>=debug的日志 loggerX.info("-------------loggerX level from RootLogger------------"); loggerX.trace("loggerX trace"); loggerX.debug("loggerX debug"); loggerX.info("loggerX info"); //將loggerX顯示設定為info級別,所以低于info級別的debug和trace都不會輸出 loggerX.info("-------------loggerX level from self------------"); loggerX.setLevel(Level.INFO); //這里的debug日志不會輸出,理由同上 loggerX.debug("loggerX-INFO debug log"); loggerX.info("loggerX-INFO info log"); loggerX.warn("loggerX-INFO warn log"); //loggerXY未配置級別,它會繼承距離它最近的父級日志級別,這里就是loggerX,所以loggerXY的級別也為INFO //debug日志不會輸出 loggerX.info("-------------loggerXY level from loggerX------------"); loggerXY.debug("loggerXY-debug debug log"); loggerXY.info("loggerXY-info info log"); loggerXY.warn("loggerXY-warn warn log"); } }
上述代碼產生的輸出如下:
17:01:33.308 [main] INFO X - -------------loggerX level from RootLogger------------ 17:01:33.310 [main] DEBUG X - loggerX debug 17:01:33.310 [main] INFO X - loggerX info 17:01:33.310 [main] INFO X - -------------loggerX level from self------------ 17:01:33.310 [main] INFO X - loggerX-INFO info log 17:01:33.310 [main] WARN X - loggerX-INFO warn log 17:01:33.310 [main] INFO X - -------------loggerXY level from loggerX------------ 17:01:33.310 [main] INFO X.Y - loggerXY-info info log 17:01:33.310 [main] WARN X.Y - loggerXY-warn warn log
相信結合代碼和輸出,應該可以充分理解logger級別的繼承關系了,
2. Appender
Appender翻譯過來就是附加器,它是附加在Logger物件上的,我們說的更直白一些,它就是指明日志輸出到哪里的一個配置項,logback支持將日志輸出到多種目標中,例如:控制臺、檔案、遠程socket服務器,資料庫、jmx等,當你配置了一個Appender,并將其附加到某個Logger物件時,就代表這個logger列印的日志會輸出到Appender指定的目標中,
一個logger可以附加多個Appender,即一個logger物件列印的日志可以輸出到多個目標中,
和logger一樣,Appender也有其繼承關系,總體來看Appender的繼承關系其實就是logger的繼承關系,只不過logger物件中有一個"附加標志位"的屬性配置會影響Appender的繼承傳遞性,下邊我們也用一個表格來說明
| Logger名稱 | 附加的Appender | 是否可附加標志位 | 輸出目標 |
| root | A1 | RootLogger作為根節點不支持該屬性 | A1 |
| x | A-x1, A-x2 | true | A-x1, A-x2 |
| x.y | none | true | A1, A-x1, A-x2 |
| x.y.z | A-xyz1 | true | A1, A-x1, A-x2, A-xyz1 |
| security | A-sec | false | A-sec |
| security.access | none | true | A-sec |
先解釋一下"附加標志位"的概念,首先它是logger物件的屬性,根據我個人的理解,它的作用是:是否阻斷向上查找繼承關系的開關,舉個例子,有三個logger,a, a.b, a.b.c,從層級關系來說,它們具有繼承關系,是祖孫三代,如果三個logger的"附加標志位"都是true,那么在查詢繼承關系時,a.b.c會先查找它的父級a.b,找到繼承關系,在向上傳遞到a,最終繼承a和a.b中所有的appender,但是如果此時a.b的"附加標志位"被配置為false了,那么a.b.c查找繼承關系時,只會查找到a.b這一級,由于a.b的"附加標志位"是false,就不會再向上查找所以a.b.c了,只會繼承a.b的Appender,而不會繼承a的Appender了,
有了上述概念我們再來分析表格中的內容:
第一行的root表示根節點,根節點Logger作為繼承結構的頂級節點,它沒有附件標志位傳遞的概念,因此root節點的Logger只會輸出到附件的A1 Appender上
第二行的x,因為它沒有任何的明確的父級,因此繼承了root節點,加上它自己的兩個Appender,它會輸出到3個Appender上
第三行x.y,從命名結構上來說,它繼承自x,而自己沒有任何Appender,所以它的繼承關系向上傳遞到x,繼承了兩個Appender,再向上到root,共繼承了三個Appender
第四行x.y.z,它直接繼承x.y,間接繼承x和root,再加上它自己的一個Appender,它共有四個Appender
第五行的可附加標志位為false,說明它不具有向上繼承的傳遞性,因此它只有自己的一個A-sec Appender
第六行繼承自security,但是由于security可附加標志位為false,因此它的繼承關系只到security,不再向上傳遞,如果security的標志位是true,那么security會默認繼承root,security.access也會向上傳遞繼承到root的Appender,
還有一個Layout組件,這里我們一句話帶過,后續用到的時候會具體說,它是一個布局器,用來配置日志輸出格式布局的,可以支持類似C語言printf的語法來格式化輸出,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/505480.html
標籤:其他
