先來看幾個例子,先想一下執行結果,答案稍後揭曉:
例一:
mylogger = logging.getlogger("mylogger")
mylogger.info("mylogger info")
mylogger.warning("mylogger warning")
例二:
mylogger = logging.getlogger("mylogger")
mylogger.setlevel(logging.info)
mylogger.info("mylogger info")
mylogger.warning("mylogger warning")
例三:
logging.info("logging info")
logging.warning("logging warning")
先來一張官方流程圖鎮樓:
日誌級別是否不低於logger級別?是的話生成一條日誌(logrecord)
logger的filter是否過濾日誌?沒過濾的話依次呼叫logger中的handler
logger是否向上傳播(propagate=true)?是的話依次呼叫父logger的handler
其次是handler流程:
日誌級別是否不低於handler級別?是的話繼續
handler的filter是否過濾日誌?沒過濾的話就可以輸出日誌
logger 類和 handler 類都繼承自 filter 類,而不是直接在 logger 類和 handler 類裡各自維護乙個 filter 列表,目的是共享 filter 類的操作**
下面揭曉幾個例子的答案,如果你都答對了,下面就不需要再看啦:
例一
>>> mylogger = logging.getlogger("mylogger")
>>> mylogger.info("mylogger info")
>>> mylogger.warning("mylogger warning")
warning:mylogger:mylogger warning
例二
>>> mylogger = logging.getlogger("mylogger")
>>> mylogger.setlevel(logging.info)
>>> mylogger.info("mylogger info")
>>> mylogger.warning("mylogger warning")
mylogger warning
例三
>>> logging.info("logging info")
>>> logging.warning("logging warning")
warning:root:logging warning
和你想的一樣嗎?不一樣的話,接著往下看
從流程圖可以看到,從呼叫logging到日誌輸出,經過了兩道關卡,首先是logger類,然後是handler類
logging模組中管理logger例項的是manager類,採用了樹形結構,最上層是 root logger ,它是所有其他logger例項的最終父節點。在源**裡,root logger 的級別被設定成 warning 。
先來看一段命令列**:
例四
>>> mylogger = logging.getlogger("mylogger")
>>> mylogger.level
0>>> mylogger.info("hello world")
>>> mylogger.warning("hello world")
hello world
>>>
mylogger 的級別是 0,也就是 logging.notset,是 logging 裡級別最低的一檔,但為什麼呼叫 info 沒有輸出呢?
原因在於,logger 類有乙個「有效級別」(effectivelevel)的概念,logger 判斷級別是用 geteffectivelevel 函式,如果 logger 例項自身的 level 是 logging.notset,函式會迭代查詢父節點的 level,直到找到乙個非零的 level,稱為**「有效級別」**。在這個例子中,mylogger的父節點就是root,所以mylogger的有效級別是warning。
那麼只要設定下mylogger的level就可以正常輸出了:
>>> mylogger.setlevel(logging.info)
>>> mylogger.info("hello world")
>>>
等等,好像還是不對?別忘了,現在只是過了logger這關,還有一關沒過呢!
handler的級別控制很簡單,只看自己本身的level,如果建立的時候沒有指定level,預設是notset,也就是不做任何過濾。
每個logger建立的時候預設是沒有handler的,建立後可以新增多個handler。
回到例四的問題,mylogger沒有handler,為什麼 mylogger.warning(「hello world」)會輸出日誌呢?
lastresort是乙個handler例項,level是warning,輸出到sys.stderr。
顧名思義,這是個「最後手段」。當logger發現自身沒有任何handler的時候,會呼叫lastresort來處理,但僅限於warning級別及以上。
所以例四的答案是:mylogger呼叫了lastresort來處理,過濾了info級別的日誌,輸出了warning級別的日誌。
root logger是比較特殊的乙個,它是在模組裡建立好的,和其他logger相比,唯一區別是預設級別warning。可以用不帶引數的logging.getlogger()方法獲取,也遵循上述兩種級別控制。
如果你想用一行**記錄日誌,一般會這樣寫:
logging.info("so easy!")
logging.warning("may be not.")
這是logging模組提供的快捷方法,實質是呼叫了root logger,但和直接呼叫root logger不同之處在於,快捷方法如果發現root logger沒有handler,還會給root logger新增乙個預設的streamhandler,level是notset,輸出到sys.stderr。
沒有指定level的logger,只能輸出warning級別及以上的日誌
沒有新增handler的logger,只能輸出warning級別及以上的日誌
直接呼叫logging.info, logging.warning函式,只能輸出warning級別及以上的日誌
回到開頭三個例子,現在你明白了嗎?
你可能不知道的東西
元素可以分為塊級元素,行內元素以及行內塊級元素。行內元素的margin或者padding只有margin left和margin right以及padding left和padding right有效果,margin top margin bottom padding top padding bot...
你可能不知道的const
眾所周知,使用 const 宣告的變數必須同時初始化為某個值。一經宣告,在其生命週期的任何時候都不能再重新賦予新值 const a syntaxerror 常量宣告時沒有初始化 const b 3 console.log b 3 b 4 typeerror 給常量賦值const 宣告只應用到頂級原語...
你可能不知道的viewport
前幾天偶然看到乙個pc端網頁,發現用手機開啟竟然同比縮放了,作為乙個前端從業者,我自然想要弄清它到底是怎麼縮放的。之後查了它的meta資訊,css和js,發現沒有任何相容手機端的 那它到底是怎麼縮放的呢?百思不得其解,最後無意中看別人說viewport的預設值是980px,才知道原來是viewpor...