標籤:篩選 情況 bsp 逗號 .net 沒有 pytho 開始 src
一 (簡單應用)
import logging logging.debug(‘debug message‘) logging.info(‘info message‘) logging.warning(‘warning message‘) logging.error(‘error message‘) logging.critical(‘critical message‘)
輸出:
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
可見,預設情況下Python的logging模組將日誌列印到了標準輸出中,且只顯示了大於等於WARNING層級的日誌,這說明預設的記錄層級設定為WARNING(記錄層級等級CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),預設的日誌格式為記錄層級:Logger名稱:使用者輸出訊息。
二 靈活配置記錄層級,日誌格式,輸出位置
import logging logging.basicConfig(level=logging.DEBUG, format=‘%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s‘, datefmt=‘%a, %d %b %Y %H:%M:%S‘, filename=‘/tmp/test.log‘, filemode=‘w‘) logging.debug(‘debug message‘) logging.info(‘info message‘) logging.warning(‘warning message‘) logging.error(‘error message‘) logging.critical(‘critical message‘)
查看輸出:
cat /tmp/test.log
Mon, 05 May 2014 16:29:53 test_logging.py[line:9] DEBUG debug message
Mon, 05 May 2014 16:29:53 test_logging.py[line:10] INFO info message
Mon, 05 May 2014 16:29:53 test_logging.py[line:11] WARNING warning message
Mon, 05 May 2014 16:29:53 test_logging.py[line:12] ERROR error message
Mon, 05 May 2014 16:29:53 test_logging.py[line:13] CRITICAL critical message
可見在logging.basicConfig()函數中可通過具體參數來更改logging模組預設行為,可用參數有
filename:用指定的檔案名稱建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被儲存在指定的檔案中。
filemode:檔案開啟檔案,在指定了filename時使用這個參數,預設值為“a”還可指定為“w”。
format:指定handler使用的日誌顯示格式。
datefmt:指定日期時間格式。
level:設定rootlogger(後邊會講解具體概念)的記錄層級
stream:用指定的stream建立StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者檔案(f=open(‘test.log‘,‘w‘)),預設為sys.stderr。若同時列出了filename和stream兩個參數,則stream參數會被忽略。
format參數中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 數字形式的記錄層級
%(levelname)s 文本形式的記錄層級
%(pathname)s 調用日誌輸出函數的模組的完整路徑名,可能沒有
%(filename)s 調用日誌輸出函數的模組的檔案名稱
%(module)s 調用日誌輸出函數的模組名
%(funcName)s 調用日誌輸出函數的函數名
%(lineno)d 調用日誌輸出函數的語句所在的程式碼
%(created)f 目前時間,用UNIX標準的表示時間的浮 點數表示
%(relativeCreated)d 輸出日誌資訊時的,自Logger建立以 來的毫秒數
%(asctime)s 字串形式的目前時間。預設格式是 “2003-07-08 16:49:45,896”。逗號後面的是毫秒
%(thread)d 線程ID。可能沒有
%(threadName)s 線程名。可能沒有
%(process)d 進程ID。可能沒有
%(message)s使用者輸出的訊息
三 logger對象
上述幾個例子中我們瞭解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分別用以記錄不同層級的日誌資訊),logging.basicConfig()(用預設日誌格式(Formatter)為日誌系統建立一個預設的流處理器(StreamHandler),設定基礎配置(如記錄層級等)並加到root logger(根Logger)中)這幾個logging模組層級別的函數,另外還有一個模組層級別的函數是logging.getLogger([name])(返回一個logger對象,如果沒有指定名字將返回root logger)
先看一個最簡單的過程:
import logginglogger = logging.getLogger()# 建立一個handler,用於寫入記錄檔fh = logging.FileHandler(‘test.log‘)# 再建立一個handler,用於輸出到控制台ch = logging.StreamHandler()formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘)fh.setFormatter(formatter)ch.setFormatter(formatter)logger.addHandler(fh) #logger對象可以添加多個fh和ch對象logger.addHandler(ch)logger.debug(‘logger debug message‘)logger.info(‘logger info message‘)logger.warning(‘logger warning message‘)logger.error(‘logger error message‘)logger.critical(‘logger critical message‘)
先簡單介紹一下,logging庫提供了多個組件:Logger、Handler、Filter、Formatter。Logger對象提供應用程式可直接使用的介面,Handler發送日誌到適當的目的地,Filter提供了過濾日誌資訊的方法,Formatter指定日誌顯示格式。
(1)
Logger是一個樹形層級結構,輸出資訊之前都要獲得一個Logger(如果沒有顯示的擷取則自動建立並使用root Logger,如第一個例子所示)。
logger = logging.getLogger()返回一個預設的Logger也即root Logger,並應用預設的記錄層級、Handler和Formatter設定。
當然也可以通過Logger.setLevel(lel)指定最低的記錄層級,可用的記錄層級有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()輸出不同層級的日誌,只有日誌等級大於或等於設定的記錄層級的日誌才會被輸出。
logger.debug(‘logger debug message‘) logger.info(‘logger info message‘) logger.warning(‘logger warning message‘) logger.error(‘logger error message‘) logger.critical(‘logger critical message‘)
只輸出了
2014-05-06 12:54:43,222 - root - WARNING - logger warning message
2014-05-06 12:54:43,223 - root - ERROR - logger error message
2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message
從這個輸出可以看出logger = logging.getLogger()返回的Logger名為root。這裡沒有用logger.setLevel(logging.Debug)顯示的為logger設定記錄層級,所以使用預設的記錄層級WARNIING,故結果只輸出了大於等於WARNIING層級的資訊。
(2) 如果我們再建立兩個logger對象:
##################################################logger1 = logging.getLogger(‘mylogger‘)logger1.setLevel(logging.DEBUG)logger2 = logging.getLogger(‘mylogger‘)logger2.setLevel(logging.INFO)logger1.addHandler(fh)logger1.addHandler(ch)logger2.addHandler(fh)logger2.addHandler(ch)logger1.debug(‘logger1 debug message‘)logger1.info(‘logger1 info message‘)logger1.warning(‘logger1 warning message‘)logger1.error(‘logger1 error message‘)logger1.critical(‘logger1 critical message‘) logger2.debug(‘logger2 debug message‘)logger2.info(‘logger2 info message‘)logger2.warning(‘logger2 warning message‘)logger2.error(‘logger2 error message‘)logger2.critical(‘logger2 critical message‘)
結果:
這裡有兩個個問題:
<1>我們明明通過logger1.setLevel(logging.DEBUG)將logger1的記錄層級設定為了DEBUG,為何顯示的時候沒有顯示出DEBUG層級的日誌資訊,而是從INFO層級的日誌開始顯示呢?
原來logger1和logger2對應的是同一個Logger執行個體,只要logging.getLogger(name)中名稱參數name相同則返回的Logger執行個體就是同一個,且僅有一個,也即name與Logger執行個體一一對應。在logger2執行個體中通過logger2.setLevel(logging.INFO)設定mylogger的記錄層級為logging.INFO,所以最後logger1的輸出遵從了後來設定的記錄層級。
<2>為什麼logger1、logger2對應的每個輸出分別顯示兩次?
這是因為我們通過logger = logging.getLogger()顯示的建立了root Logger,而logger1 = logging.getLogger(‘mylogger‘)建立了root Logger的孩子(root.)mylogger,logger2同樣。而孩子,孫子,重孫……既會將訊息分發給他的handler進行處理也會傳遞給所有的祖先Logger處理。
ok,那麼現在我們把
# logger.addHandler(fh)
# logger.addHandler(ch) 注釋掉,我們再來看效果:
因為我們注釋了logger對象顯示的位置,所以才用了預設,即標準輸出方式。因為它的父級沒有設定檔案顯示方式,所以在這裡只列印了一次。
孩子,孫子,重孫……可逐層繼承來自祖先的記錄層級、Handler、Filter設定,也可以通過Logger.setLevel(lel)、Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)、Logger.addFilter(filt)、Logger.removeFilter(filt)。設定自己特別的記錄層級、Handler、Filter。若不設定則使用繼承來的值。
<3>Filter
限制只有滿足過濾規則的日誌才會輸出。
比如我們定義了filter = logging.Filter(‘a.b.c‘),並將這個Filter添加到了一個Handler上,則使用該Handler的Logger中只有名字帶 a.b.c首碼的Logger才能輸出其日誌。
filter = logging.Filter(‘mylogger‘)
logger.addFilter(filter)
這是只對logger這個對象進行篩選
如果想對所有的對象進行篩選,則:
filter = logging.Filter(‘mylogger‘)
fh.addFilter(filter)
ch.addFilter(filter)
這樣,所有添加fh或者ch的logger對象都會進行篩選。
完整代碼1:
View Code
完整代碼2:
View Code
應用:
View Code
Python logging模組