使用python的logging模塊

一、從一個使用場景開始

 

開發一個日誌系統, 既要把日誌輸出到控制檯, 還要寫入日誌文件

 

import logging

# 創建一個logger
logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)

# 創建一個handler,用於寫入日誌文件
fh = logging.FileHandler('test.log')
fh.setLevel(logging.DEBUG)

# 再創建一個handler,用於輸出到控制檯
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

# 定義handler的輸出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)

# 給logger添加handler
logger.addHandler(fh)
logger.addHandler(ch)

# 記錄一條日誌
logger.info('foorbar')
 

 

運行後, 在控制檯和日誌文件都有一條日誌:

 

2011-08-31 19:18:29,816 - mylogger - INFO - foorbar

 

 

二、logging模塊的API

 

結合上面的例子,我們說下幾個最常使用的API

logging.getLogger([name]) 返回一個logger實例,如果沒有指定name,返回root logger。 只要name相同,返回的logger實例都是同一個而且只有一個,即name和logger實例是 一一對應的。這意味着,無需把logger實例在各個模塊中傳遞。只要知道name,就能得到 同一個logger實例
Logger.setLevel(lvl) 設置logger的level, level有以下幾個級別:

NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL
如果把looger的級別設置爲INFO, 那麼小於INFO級別的日誌都不輸出, 大於等於INFO級 別的日誌都輸出
logger.debug("foobar")    # 不輸出 
logger.info("foobar")        # 輸出
logger.warning("foobar") # 輸出
logger.error("foobar")      # 輸出
logger.critical("foobar")    # 輸出
  Logger.addHandler(hdlr) logger可以僱傭handler來幫它處理日誌, handler主要有以下幾種: StreamHandler: 輸出到控制檯 FileHandler:   輸出到文件 handler還可以設置自己的level以及輸出格式。
logging.basicConfig([**kwargs]) * 這個函數用來配置root logger, 爲root logger創建一個StreamHandler,    設置默認的格式。 * 這些函數: logging.debug()、logging.info()、logging.warning()、    logging.error()、logging.critical() 如果調用的時候發現root logger沒有任何    handler, 會自動調用basicConfig添加一個handler * 如果root logger已有handler, 這個函數不做任何事情
使用basicConfig來配置root logger的輸出格式和level:
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should appear on the console')
 
三、關於root logger以及logger的父子關係
前面多次提到root logger, 實際上logger實例之間還有父子關係, root logger就是處於 最頂層的logger, 它是所有logger的祖先。如下圖: root logger是默認的logger 如果不創建logger實例, 直接調用logging.debug()、logging.info()logging.warning()、logging.error()、logging.critical()這些函數, 那麼使用的logger就是 root logger, 它可以自動創建,也是單實例的。
如何得到root logger 通過logging.getLogger()或者logging.getLogger("")得到root logger實例。
默認的level root logger默認的level是logging.WARNING
如何表示父子關係 logger的name的命名方式可以表示logger之間的父子關係. 比如: parent_logger = logging.getLogger('foo') child_logger = logging.getLogger('foo.bar')
什麼是effective level logger有一個概念,叫effective level。 如果一個logger沒有顯示地設置level,那麼它就 用父親的level。如果父親也沒有顯示地設置level, 就用父親的父親的level,以此推.... 最後到達root logger,一定設置過level。默認爲logging.WARNING child loggers得到消息後,既把消息分發給它的handler處理,也會傳遞給所有祖先logger處理,
來看一個例子
import logging

# 設置root logger
r = logging.getLogger()
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
r.addHandler(ch)

# 創建一個logger作爲父親
p = logging.getLogger('foo')
p.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(message)s')
ch.setFormatter(formatter)
p.addHandler(ch)

# 創建一個孩子logger
c = logging.getLogger('foo.bar')
c.debug('foo')
  輸出如下:
2011-08-31 21:04:29,893 - foo
2011-08-31 21:04:29,893 - DEBUG - foo

可見, 孩子logger沒有任何handler,所以對消息不做處理。但是它把消息轉發給了它的父 親以及root logger。最後輸出兩條日誌。
發佈了29 篇原創文章 · 獲贊 4 · 訪問量 7443
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章