1. 程式人生 > >Python日誌模塊logging

Python日誌模塊logging

python logging 日誌

日誌對於程序運行和技術人員來說是很必要且非常重要的,排查問題一般都是從分析程序運行日誌開始的,再復雜再龐大的程序都必須要有日誌輸入,否則就算不上合格的程序。Python中為技術人員提供了方便的logging模塊來定義和輸出日誌。

先來看下logging的日誌級別和簡單的輸出,如下例子:

#導入日誌模塊logging
import logging
# 輸出不同級別的log
logging.debug(‘This is debug info‘)
logging.info(‘This is information‘)
logging.warn(‘This is warning message‘)
logging.error(‘This is error message‘)
logging.fatal(‘This is fatal message, it is same as logger.critical‘)
logging.critical(‘This is critical message‘)

運行結果:
WARNING:root:This is warning message
ERROR:root:This is error message
CRITICAL:root:This is fatal message, it is same as logger.critical
CRITICAL:root:This is critical message

從上述例子中可以看出默認情況下python的logging模塊將日誌打印到了標準輸出中,且只顯示了大於等於WARNING級別的日誌,這說明默認的日誌級別設置為WARNING(日誌級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默認的日誌格式為日誌級別:Logger名稱(默認的logger名稱是root

):用戶輸出消息。

我們可以通過logging模塊的basicConfig函數對輸出日誌格式、位置、級別進行自定義,如下例子:

#basicConfig定義日誌級別,日誌格式,輸出位置
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=‘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 test.log
Thu, 10 Nov 2017 10:03:44 rizhi.py[line:20] DEBUG debug message
Thu, 10 Nov 2017 10:03:44 rizhi.py[line:21] INFO info message
Thu, 10 Nov 2017 10:03:44 rizhi.py[line:22] WARNING warning message
Thu, 10 Nov 2017 10:03:44 rizhi.py[line:23] ERROR error message
Thu, 10 Nov 2017 10:03:44 rizhi.py[line:24] CRITICAL critical message

從例子中看出在logging.basicConfig()函數中可通過具體參數來更改logging模塊默認行為,可用參數有:
filename:用指定的文件名,這樣日誌會被存儲在指定的文件中。
filemode:文件打開方式,在指定了filename時使用這個參數,默認值為“a”還可指定為“w”。
format:指定使用的日誌顯示格式。
datefmt:指定日期時間格式。
level:設置的日誌級別
stream:用指定的stream創建StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者文件,默認為 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 用戶輸出的消息

logging.basicConfig()函數提供的日誌輸出方式已經足夠靈活,但還有另外一個更靈活的模塊級函數logging.getLogger(),返回一個logger對象,如果沒有指定名字將返回root logger。為了了解這個函數,我們需要先了解下Logger,Handler,Formatter,Filter的概念。

Logger對象提供應用程序可直接使用的接口,Handler發送日誌到適當的目的地,Filter提供了過濾日誌信息的方法,Formatter指定日誌顯示格式。

例子:演示 logging.getLogger()用法

import logging
# 創建一個logger
logger = logging.getLogger()
logger1 = logging.getLogger(‘mylogger‘)
logger1.setLevel(logging.DEBUG)
logger2 = logging.getLogger(‘mylogger‘)
logger2.setLevel(logging.INFO)
logger3 = logging.getLogger(‘mylogger.child1‘)
logger3.setLevel(logging.WARNING)
# 創建一個handler,用於寫入日誌文件
fh = logging.FileHandler(‘test.log‘)
# 再創建一個handler,用於輸出到控制臺
ch = logging.StreamHandler()
# 定義handler的輸出格式formatter
formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# 定義一個filter
filter1 = logging.Filter(‘mylogger‘)
filter2 = logging.Filter(‘mylogger.child1‘)
# fh.addFilter(filter)
# 給logger添加handler
logger.addHandler(fh)
logger.addHandler(ch)
logger1.addFilter(filter1)
logger1.addHandler(fh)
logger1.addHandler(ch)
logger2.addFilter(filter1)
logger2.addHandler(fh)
logger2.addHandler(ch)
logger3.addFilter(filter2)
logger3.addHandler(fh)
logger3.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‘)
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‘)
logger3.debug(‘logger3 debug message‘)
logger3.info(‘logger3 info message‘)
logger3.warning(‘logger3 warning message‘)
logger3.error(‘logger3 error message‘)
logger3.critical(‘logger3 critical message‘)

運行結果:
2017-11-09 22:51:59,654 - root - WARNING - logger warning message
2017-11-09 22:51:59,654 - root - ERROR - logger error message
2017-11-09 22:51:59,654 - root - CRITICAL - logger critical message
2017-11-09 22:51:59,655 - mylogger - INFO - logger1 info message
2017-11-09 22:51:59,655 - mylogger - INFO - logger1 info message
2017-11-09 22:51:59,655 - mylogger - WARNING - logger1 warning message
2017-11-09 22:51:59,655 - mylogger - WARNING - logger1 warning message
2017-11-09 22:51:59,655 - mylogger - ERROR - logger1 error message
2017-11-09 22:51:59,655 - mylogger - ERROR - logger1 error message
2017-11-09 22:51:59,655 - mylogger - CRITICAL - logger1 critical message
2017-11-09 22:51:59,655 - mylogger - CRITICAL - logger1 critical message
2017-11-09 22:51:59,655 - mylogger - INFO - logger2 info message
2017-11-09 22:51:59,655 - mylogger - INFO - logger2 info message
2017-11-09 22:51:59,655 - mylogger - WARNING - logger2 warning message
2017-11-09 22:51:59,655 - mylogger - WARNING - logger2 warning message
2017-11-09 22:51:59,655 - mylogger - ERROR - logger2 error message
2017-11-09 22:51:59,655 - mylogger - ERROR - logger2 error message
2017-11-09 22:51:59,655 - mylogger - CRITICAL - logger2 critical message
2017-11-09 22:51:59,655 - mylogger - CRITICAL - logger2 critical message
2017-11-09 22:51:59,657 - mylogger.child1 - WARNING - logger3 warning message
2017-11-09 22:51:59,657 - mylogger.child1 - WARNING - logger3 warning message
2017-11-09 22:51:59,657 - mylogger.child1 - WARNING - logger3 warning message
2017-11-09 22:51:59,657 - mylogger.child1 - ERROR - logger3 error message
2017-11-09 22:51:59,657 - mylogger.child1 - ERROR - logger3 error message
2017-11-09 22:51:59,657 - mylogger.child1 - ERROR - logger3 error message
2017-11-09 22:51:59,657 - mylogger.child1 - CRITICAL - logger3 critical message
2017-11-09 22:51:59,657 - mylogger.child1 - CRITICAL - logger3 critical message
2017-11-09 22:51:59,657 - mylogger.child1 - CRITICAL - logger3 critical message

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()輸出不同級別的日誌,只有日誌等級大於或等於設置的日誌級別的日誌才會被輸出。

(1)從上述例子中可以發現通過logger1.setLevel(logging.DEBUG)將logger1的日誌級別設置為了DEBUG,但沒有輸出DEBUG級別的日誌信息,而是從INFO級別的日誌開始了顯示,這是因為logger1和logger2對應的是同一個Logger實例mylogger,只要logging.getLogger(name)中名稱參數name相同則返回的Logger實例就是同一個,且僅有一個,也即name與Logger實例一一對應。在logger2實例中通過logger2.setLevel(logging.INFO)設置mylogger的日誌級別為logging.INFO,所以最後logger1的輸出遵從了後來設置的日誌級別。

logger1 = logging.getLogger(‘mylogger‘)
logger1.setLevel(logging.DEBUG)
logger2 = logging.getLogger(‘mylogger‘)
logger2.setLevel(logging.INFO)

(2)從例子輸出可以看出logger1、logger2對應的每個輸出分別顯示兩次,logger3對應的輸出顯示3次,這是因為通過logger = logging.getLogger()顯示的創建了root Logger,而logger1 = logging.getLogger(‘mylogger‘)創建了root Logger的子類(root.)mylogger,以此類推,logger2同樣。

logger3 = logging.getLogger(‘mylogger.child1‘)
logger3.setLevel(logging.WARNING)

(3)Formatter對象設置日誌信息最後的規則、結構和內容,默認的時間格式為%Y-%m-%d %H:%M:%S。

formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘)
fh.setFormatter(formatter)
ch.setFormatter(formatter)

(4)Filter限制只有滿足過濾規則的日誌才會輸出。比如我們定義了filter = logging.Filter(‘a.b.c‘),並將這個Filter添加到了一個Handler上,則使用該Handler的Logger中只有名字帶a.b.c前綴的Logger才能輸出其日誌。

filter1 = logging.Filter(‘mylogger‘)
filter2 = logging.Filter(‘mylogger.child1‘)

本文出自 “DreamScape” 博客,請務必保留此出處http://dyqd2011.blog.51cto.com/3201444/1980519

Python日誌模塊logging