Python logging 模塊定義了為應用程式和庫實現靈活的事件日誌記錄的函數和類。
程序開發過程中,很多程序都有記錄日誌的需求,並且日誌包含的信息有正常的程序訪問日誌還可能有錯誤、警告等信息輸出,Python 的 logging 模塊提供了標準的日誌接口,可以通過它存儲各種格式的日誌,日誌記錄提供了一組便利功能,用於簡單的日誌記錄用法。
日誌記錄函數以它們用來跟蹤的事件的級別或嚴重性命名。下面描述了標準級別及其適用性(從高到低的順序):
日誌等級(level)描述DEBUG最詳細的日誌信息,典型應用場景是 問題診斷INFO信息詳細程度僅次於DEBUG,通常只記錄關鍵節點信息,用於確認一切都是按照我們預期的那樣進行工作WARNING當某些不期望的事情發生時記錄的信息(如,磁碟可用空間較低),但是此時應用程式還是正常運行的ERROR由於一個更嚴重的問題導致某些功能不能正常運行時記錄的信息CRITICAL當發生嚴重錯誤,導致應用程式不能繼續運行時記錄的信息日誌級別等級排序:critical > error > warning > info > debug
級別越高列印的日誌越少,反之亦然,即
debug : 列印全部的日誌( notset 等同於 debug )
info : 列印 info, warning, error, critical 級別的日誌
warning : 列印 warning, error, critical 級別的日誌
error : 列印 error, critical 級別的日誌
critical : 列印 critical 級別
一、 Logging 模塊日誌記錄方式Logging 模塊提供了兩種日誌記錄方式:
1、Logging 定義的模塊級別函數函數說明logging.debug(msg, *args, **kwargs)創建一條嚴重級別為DEBUG的日誌記錄logging.info(msg, *args, **kwargs)創建一條嚴重級別為INFO的日誌記錄logging.warning(msg, *args, **kwargs)創建一條嚴重級別為WARNING的日誌記錄logging.error(msg, *args, **kwargs)創建一條嚴重級別為ERROR的日誌記錄logging.critical(msg, *args, **kwargs)創建一條嚴重級別為CRITICAL的日誌記錄logging.log(level, *args, **kwargs)創建一條嚴重級別為level的日誌記錄logging.basicConfig(**kwargs)對root logger進行一次性配置簡單列印日誌:
import logging
# 列印日誌級別def test_logging(): logging.debug('Python debug') logging.info('Python info') logging.warning('Python warning') logging.error('Python Error') logging.critical('Python critical')
test_logging()輸出結果:
WARNING:root:Python warningERROR:root:Python ErrorCRITICAL:root:Python critical當指定一個日誌級別之後,會記錄大於或等於這個日誌級別的日誌信息,小於的將會被丟棄,==默認情況下日誌列印只顯示大於等於 WARNING 級別的日誌。==
1.1 設置日誌顯示級別通過 logging.basicConfig() 可以設置 root 的日誌級別,和日誌輸出格式。
logging.basicConfig() 關鍵字參數:
關鍵字描述filename創建一個 FileHandler,使用指定的文件名,而不是使用 StreamHandler。filemode如果指明了文件名,指明打開文件的模式(如果沒有指明 filemode,默認為 'a')。formathandler 使用指明的格式化字符串。datefmthandler 使用指明的格式化字符串。level指明根 logger 的級別。stream使用指明的流來初始化 StreamHandler。該參數與 'filename' 不兼容,如果兩個都有,'stream' 被忽略。format 格式
格式描述%(levelno)s列印日誌級別的數值%(levelname)s列印日誌級別名稱%(pathname)s列印當前執行程序的路徑%(filename)s列印當前執行程序名稱%(funcName)s列印日誌的當前函數%(lineno)d列印日誌的當前行號%(asctime)s列印日誌的時間%(thread)d列印線程 ID%(threadName)s列印線程名稱%(process)d列印進程 ID%(message)s列印日誌信息注意:Logging.basicConfig() 需要在開頭就設置,在中間設置並無作用
實例
import logging
# 列印日誌級別def test(): logging.basicConfig(level=logging.DEBUG) logging.debug('Python debug') logging.info('Python info') logging.warning('Python warning') logging.error('Python Error') logging.critical('Python critical') logging.log(2,'test')test()輸出:
DEBUG:root:Python debugINFO:root:Python infoWARNING:root:Python warningERROR:root:Python ErrorCRITICAL:root:Python critical1.2 將日誌信息記錄到文件# 日誌信息記錄到文件logging.basicConfig(filename='F:/example.log', level=logging.DEBUG)logging.debug('This message should go to the log file')logging.info('So should this')logging.warning('And this, too')在相應的路徑下會有 example.log 日誌文件,內容如下:
DEBUG:root:This message should go to the log fileINFO:root:So should thisWARNING:root:And this, too1.3 多個模塊記錄日誌信息如果程序包含多個模塊,則用以下實例來顯示日誌信息:實例中有兩個模塊,一個模塊通過導入另一個模塊的方式用日誌顯示另一個模塊的信息:
myapp.py 模塊
import loggingimport mylibdef main(): logging.basicConfig(filename='myapp.log',level=logging.DEBUG) logging.info('Started') mylib.do_something() logging.info('Finished')
if __name__ == '__main__': main()mylib.py 模塊
import logging
def do_something(): logging.info('Doing something')執行 myapp.py 模塊會列印相應日誌,在文件 myapp.log 中顯示信息如下:
INFO:root:StartedINFO:root:Doing somethingINFO:root:Finishe1.4 顯示信息的日期及更改顯示消息格式顯示消息日期
import logging# 顯示消息時間logging.basicConfig(format='%(asctime)s %(message)s')logging.warning('is when this event was logged.')
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')logging.warning('is when this event was logged.')結果:
2019-10-16 18:57:45,988 is when this event was logged.2019-10-16 18:57:45,988 is when this event was logged.更改顯示消息格式
import logging# 更改顯示消息的格式logging.basicConfig(format='%(levelname)s:%(message)s',level=logging.DEBUG)logging.debug('Python message format Debug')logging.info('Python message format Info')logging.warning('Python message format Warning')結果:
DEBUG:Python message format DebugINFO:Python message format InfoWARNING:Python message format Warning==注意==:顯示結果只顯示級別和具體信息,之前顯示的 「根」 已經消失,重新定義的格式修改了默認輸出方式。
2、logging 模塊四大組件組件名稱對應類名功能描述日誌器Logger暴露函數給應用程式,基於日誌記錄器和過濾器級別決定哪些日誌有效處理器Handler將 logger 創建的日誌記錄發送到合適的目的輸出過濾器Filter提供了更細粒度的控制工具來決定輸出哪條日誌記錄,丟棄哪條日誌記錄格式器Formatter決定日誌記錄的最終輸出格式2.1 日誌器- LoggerLogger 持有日誌記錄器的方法,日誌記錄器不直接實例化,而是通過模塊級函數 logger.getlogger (name) 來實例化,使用相同的名稱多次調用 getLogger() 總是會返回對相同 Logger 對象的引用。
應用程式代碼能直接調用日誌接口。
Logger最常用的操作有兩類:配置和發送日誌消息。
初始化 logger = logging.getLogger("endlesscode"),獲取 logger 對象,getLogger() 方法後面最好加上所要日誌記錄的模塊名字,配置文件和列印日誌格式中的 %(name)s 對應的是這裡的模塊名字,如果不指定name則返回root對象。
logger.setLevel(logging.DEBUG),Logging 中有 NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL這幾種級別,日誌會記錄設置級別以上的日誌
多次使用相同的name調用 getLogger 方法返回同一個 looger 對象;
Logger是一個樹形層級結構,在使用接口 debug,info,warn,error,critical 之前必須創建 Logger 實例:
創建方法: logger = logging.getLogger(logger_name)創建Logger實例後,可以使用以下方法進行日誌級別設置,增加處理器 Handler:
logger.setLevel(logging.ERROR) # 設置日誌級別為 ERROR,即只有日誌級別大於等於 ERROR 的日誌才會輸出
logger.addHandler(handler_name) # 為 Logger 實例增加一個處理器
logger.removeHandler(handler_name) # 為 Logger 實例刪除一個處理器
2.2 處理器- HandlerHandler 處理器類型有很多種,比較常用的有三個,StreamHandler,FileHandler,NullHandler
StreamHandler
創建方法:sh = logging.StreamHandler(stream=None)創建 StreamHandler 之後,可以通過使用以下方法設置日誌級別,設置格式化器 Formatter,增加或刪除過濾器 Filter:
ch.setLevel(logging.WARN) # 指定日誌級別,低於WARN級別的日誌將被忽略
ch.setFormatter(formatter_name) # 設置一個格式化器formatter
ch.addFilter(filter_name) # 增加一個過濾器,可以增加多個 ch.removeFilter(filter_name) # 刪除一個過濾器2.3 過濾器- FilterHandlers 和 Loggers 可以使用 Filters 來完成比級別更複雜的過濾。Filter 基類只允許特定 Logger 層次以下的事件。例如用 『A.B』 初始化的 Filter 允許Logger 『A.B』, 『A.B.C』, 『A.B.C.D』, 『A.B.D』 等記錄的事件,logger『A.BB』, 『B.A.B』 等就不行。如果用空字符串來初始化,所有的事件都接受。
創建方法: filter = logging.Filter(name='')2.4 格式器- Formatter使用Formatter對象設置日誌信息最後的規則、結構和內容,默認的時間格式為%Y-%m-%d %H:%M:%S。
創建方法: formatter = logging.Formatter(fmt=None, datefmt=None)其中,fmt 是消息的格式化字符串,datefmt 是日期字符串。如果不指明 fmt,將使用 '%(message)s' 。如果不指明 datefmt,將使用 ISO8601 日期格式。
2.5 組件之間的關聯關係日誌器(logger)需要通過處理器(handler)將日誌信息輸出到目標位置,不同的處理器(handler)可以將日誌輸出到不同的位置;
日誌器(logger)可以設置多個處理器(handler)將同一條日誌記錄輸出到不同的位置;
每個處理器(handler)都可以設置自己的過濾器(filter)實現日誌過濾,從而只保留感興趣的日誌;
每個處理器(handler)都可以設置自己的格式器(formatter)實現同一條日誌以不同的格式輸出到不同的地方。
簡明了說就是:日誌器(logger)是入口,真正幹活兒的是處理器(handler),處理器(handler)還可以通過過濾器(filter)和格式器(formatter)對要輸出的日誌內容做過濾和格式化等處理操作。
Logger 可以包含一個或多個 Handler 和 Filter
Logger 與 Handler 或 Fitler 是一對多的關係
一個 Logger 實例可以新增多 個 Handler,一個 Handler 可以新增多個格式化器或多個過濾器,而且日誌級別將會繼承。
二、Logging 日誌工作流程1、Logging 模塊使用過程1)第一次導入 logging 模塊或使用 reload 函數重新導入 logging 模塊,logging 模塊中的代碼將被執行,這個過程中將產生 logging 日誌系統的默認配置。
2、Logging 模塊處理流程 logging 處理流程
2)自定義配置(可選),logging標準模塊支持三種配置方式: dictConfig,fileConfig,listen。其中,dictConfig 是通過一個字典進行配置 Logger,Handler,Filter,Formatter;fileConfig 則是通過一個文件進行配置;而 listen 則監聽一個網絡埠,通過接收網絡數據來進行配置。當然,除了以上集體化配置外,也可以直接調用 Logger,Handler 等對象中的方法在代碼中來顯式配置。
3)使用 logging 模塊的全局作用域中的 getLogger 函數來得到一個 Logger 對象實例(其參數即是一個字符串,表示 Logger 對象實例的名字,即通過該名字來得到相應的 Logger 對象實例)。
4)使用 Logger 對象中的 debug,info,error,warn,critical 等方法記錄日誌信息。流程描述:
判斷日誌的等級是否大於 Logger 對象的等級,如果大於,則往下執行,否則,流程結束。
產生日誌:第一步,判斷是否有異常,如果有,則添加異常信息。第二步,處理日誌記錄方法(如 debug,info 等)中的佔位符,即一般的字符串格式化處理。
使用註冊到 Logger 對象中的 Filters 進行過濾。如果有多個過濾器,則依次過濾;只要有一個過濾器返回假,則過濾結束,且該日誌信息將丟棄,不再處理,而處理流程也至此結束。否則,處理流程往下執行。
在當前 Logger 對象中查找 Handlers,如果找不到任何 Handler,則往上到該 Logger 對象的父 Logger 中查找;如果找到一個或多個 Handler,則依次用 Handler 來處理日誌信息。但在每個 Handler 處理日誌信息過程中,會首先判斷日誌信息的等級是否大於該 Handler 的等級,如果大於,則往下執行(由 Logger 對象進入 Handler 對象中),否則,處理流程結束。
執行 Handler 對象中的 filter 方法,該方法會依次執行註冊到該 Handler 對象中的 Filter。如果有一個 Filter 判斷該日誌信息為假,則此後的所有 Filter 都不再執行,而直接將該日誌信息丟棄,處理流程結束。
使用 Formatter 類格式化最終的輸出結果。註:Formatter 同上述第 2 步的字符串格式化不同,它會添加額外的信息,比如日誌產生的時間,產生日誌的原始碼所在的源文件的路徑等等。
真正地輸出日誌信息(到網絡,文件,終端,郵件等)。至於輸出到哪個目的地,由 Handler 的種類來決定。
三、配置日誌程式設計師可以通過三種方式配置日誌記錄:
1、使用配置方法的 Python 代碼顯式創建記錄器,處理程序和格式化程序。
2、創建日誌記錄配置文件並使用該 fileConfig() 功能讀取它。
3、創建配置信息字典並將其傳遞給 dictConfig()函數。下面使用 Python 代碼配置一個非常簡單的記錄器,一個控制臺處理程序和一個簡單的格式化程序:
logging.conf 配置文件:
[loggers]keys=root,simpleExample
[handlers]keys=consoleHandler
[formatters]keys=simpleFormatter
[logger_root]level=DEBUGhandlers=consoleHandler
[logger_simpleExample]level=DEBUGhandlers=consoleHandlerqualname=simpleExamplepropagate=0
[handler_consoleHandler]class=StreamHandlerlevel=DEBUGformatter=simpleFormatterargs=(sys.stdout,)
[formatter_simpleFormatter]format=%(asctime)s - %(name)s - %(levelname)s - %(message)sdatefmt=config_logging.py 配置器:
import logging# create loggerlogger = logging.getLogger('simple_example')logger.setLevel(logging.DEBUG)
# create console handler and set level to debugch = logging.StreamHandler()ch.setLevel(logging.DEBUG)
# create formatterformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to chch.setFormatter(formatter)
# add ch to loggerlogger.addHandler(ch)
# 'application' codelogger.debug('debug message')logger.info('info message')logger.warning('warn message')logger.error('error message')logger.critical('critical message')recorder 記錄器:
import loggingimport logging.config
logging.config.fileConfig('logging.conf')
# create loggerlogger = logging.getLogger('simpleExample')
# 'application' codelogger.debug('debug message')logger.info('info message')logger.warning('warn message')logger.error('error message')logger.critical('critical message')運行結果:
2019-10-16 19:45:34,440 - simple_example - DEBUG - debug message2019-10-16 19:45:34,440 - simple_example - INFO - info message2019-10-16 19:45:34,440 - simple_example - WARNING - warn message2019-10-16 19:45:34,440 - simple_example - ERROR - error message2019-10-16 19:45:34,441 - simple_example - CRITICAL - critical message總結本章節給大家介紹了 Python 標準庫中 Logging 模塊的詳細介紹與使用,對 Python 工程師使用該模塊提供更好的支撐
參考:https://docs.python.org/3.6/library/logging.html?highlight=logging#integration-with-the-warnings-modulehttps://www.jianshu.com/p/feb86c06c4f4
https://cloud.tencent.com/developer/article/1354396