logging模塊是Python的一個標準庫模塊,開發過程當中,能夠經過該模塊,靈活的完成日誌的記錄。ide
logging模塊提供了兩種記錄日誌的方式:
1)使用logging提供的模塊級別的函數(logging.basicConfig,logging.debug,logging.info...)
2)使用logging模塊的組件(loggers,handlers,filters,formatters)函數
下面會分別介紹這兩種方式,這裏建議使用第二種方式,使用 logging模塊的組件能夠更靈活的完成日誌記錄~線程
logging模塊的日誌級別(level)包括:DEBUG,INFO,WARNING,ERROR,CRITICAL~debug
日誌級別(level) | 描述 |
---|---|
DEBUG | 調試級別,通常用於問題的排查,日誌的信息最爲詳細 |
INFO | 僅記錄普通的信息,日誌信息的詳細程度僅次於DEBUG |
WARNING | 警告信息,通常這類信息不會影響程序的正常運行 |
ERROR | 錯誤信息, 出現錯誤信息時,程序通常已不能正常運行 |
CRITICAL | 更嚴重的錯誤信息,程序不能繼續運行 |
從 DEBUG 到 CRITICAL,日誌等級依次提升,即嚴重性逐步提高,日誌的信息量依次減小:
DEBUG < INFO < WARNING < ERROR < CRITICAL調試
示例以下:日誌
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 # 默認的日誌格式:日誌級別 : Logger名稱 : 用戶輸出消息。 ERROR:root:error message CRITICAL:root:critical message
這裏僅輸出了大於等於WARNING級別的日誌,說明 logging模塊 默認的日誌級別爲WARNING,即日誌級別大於等於WARNING的纔會被輸出,且默認狀況下,日誌會直接打印到標準輸出中~
經過 logging模塊 的basicConfig函數可靈活地配置日誌級別,日誌格式以及日誌的輸出位置:code
import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', # 日誌格式 datefmt='%Y-%m-%d %H:%M:%S', # 時間格式:2018-11-12 23:50:21 filename='/tmp/test.log', # 日誌的輸出路徑 filemode='a') # 追加模式 logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
程序運行後,日誌信息會直接記錄到 指定的文件中(/tmp/test.log),且日誌級別爲DEBUG,因此全部的日誌都會被輸出,日誌信息以下:orm
➜ ~ cat /tmp/test.log 2018-11-12 23:50:49 test.py[line:9] DEBUG debug message 2018-11-12 23:50:49 test.py[line:10] INFO info message 2018-11-12 23:50:49 test.py[line:11] WARNING warning message 2018-11-12 23:50:49 test.py[line:12] ERROR error message 2018-11-12 23:50:49 test.py[line:13] CRITICAL critical message
logging.basicConfig()函數中可經過具體參數來更改logging模塊默認行爲,可用參數有:對象
filename:用指定的文件名建立FiledHandler,這樣日誌會被存儲在指定的文件中。
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 字符串形式的當前時間。默認格式是 「2018-11-13 00:00:00,896」。逗號後面的是毫秒
%(thread)d 線程ID。可能沒有
%(threadName)s 線程名。可能沒有
%(process)d 進程ID。可能沒有
%(message)s用戶輸出的消息接口
使用logging模塊級別的函數記錄日誌,沒法實現將日誌輸出到多個路徑下。這裏logging模塊提供了4個組件,經過這些組件可實現將日誌輸出到多個路徑下,且每一個路徑下的日誌格式可單獨配置~
組件名稱 | 功能描述 |
---|---|
Logger | 日誌器,提供了應用程序可一直使用的接口 |
Handler | 將 logger 產生的日誌發送到指定的路徑下(例如能夠是終端,也能夠是文件) |
Filter | 如有多個 Logger,可根據名稱過濾出指定的 Logger 來記錄日誌 |
Formatter | 定義日誌格式 |
使用組件記錄日誌的大體步驟以下:
1)logging.getLogger() 獲取 logger對象
2)建立一個或多個 handler,用於指定日誌信息的輸出流向
3)建立一個或多個 formatter,指定日誌的格式,並分別將 formatter 綁定到 上
4)將 handler 綁定到 logger對象 上
5)logger.setLevel(logging.DEBUG) 設置日誌級別
5)最後即可使用 logger對象 記錄日誌~
示例
import logging # 獲取 logger對象 logger = logging.getLogger() # 建立一個 handler,用於寫入日誌文件 fh = logging.FileHandler('/tmp/test.log') # 再建立一個 handler,用於輸出到控制檯 ch = logging.StreamHandler() # 建立一個 formatter,兩個 handler 使用相同的日誌格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 綁定 formatter 到 handler 上 fh.setFormatter(formatter) ch.setFormatter(formatter) # 綁定 handler 到 logger對象 上 logger.addHandler(fh) #logger對象能夠添加多個fh和ch對象 logger.addHandler(ch) # 設置日誌級別 logger.setLevel(logging.WARNING) 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')
查看輸出結果:
終端輸出: 2018-11-13 23:14:09,161 - root - WARNING - logger warning message 2018-11-13 23:14:09,161 - root - ERROR - logger error message 2018-11-13 23:14:09,161 - root - CRITICAL - logger critical message 文件輸出: ➜ ~ cat /tmp/test.log 2018-11-13 23:14:09,161 - root - WARNING - logger warning message 2018-11-13 23:14:09,161 - root - ERROR - logger error message 2018-11-13 23:14:09,161 - root - CRITICAL - logger critical message
也能夠經過 handler 來設置日誌級別,當使用 handler 來設置日誌級別時,存在以下兩種狀況:
1)若 handler 設置的日誌級別小於等於 logger 的日誌級別時,則以logger 的日誌級別爲準;
2)若 handler 設置的日誌級別大於 logger 的日誌級別時,則以handler 的日誌級別爲準;
簡單而言就是,二者同時設置日誌級別,以日誌級別高的爲準。因爲不設置 logger 的日誌級別,其默認日誌級別就是 WARNING,因此不存在 handler 單獨設置日誌級別的狀況~
經過示例來驗證:
1)logger 日誌級別設置爲 DEBUG,logger 不設置(默認爲WARNING)
import logging logger = logging.getLogger() ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch.setLevel(logging.DEBUG) # logger.setLevel(logging.CRITICAL) ch.setFormatter(formatter) 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') 輸出結果: 2018-11-13 23:40:13,829 - root - WARNING - logger warning message 2018-11-13 23:40:13,829 - root - ERROR - logger error message 2018-11-13 23:40:13,829 - root - CRITICAL - logger critical message
2)logger 日誌級別設置爲 CRITICAL,logger 設置爲 ERROR
import logging logger = logging.getLogger() ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch.setLevel(logging.CRITICAL) logger.setLevel(logging.ERROR) ch.setFormatter(formatter) 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') 輸出結果: 2018-11-13 23:41:51,279 - root - CRITICAL - logger critical message
filter組件用來過濾 logger 對象,一個 filter 能夠直接添加到 logger對象上,也能夠添加到 handler 對象上。
例如,定義一個filter: filter = logging.Filter('a.b'),當把這個 filter 添加到一個 handler 上,那麼綁定了該 handler 的 多個 logger對象中,只有名字是 'a.b' 前綴的才能經過該 handler 輸出日誌~
在 handler 上添加 filter:
import logging logger1 = logging.getLogger('a.b.c') logger2 = logging.getLogger('a.c') # 定義一個 filter filter = logging.Filter(name='a.b') # 定義一個 handler ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter) # 若兩個 logger對象 的日誌級別相同,且都是用經過一個 handler,能夠在這個 handler 上設置日誌級別 ch.setLevel(logging.ERROR) # 在 handler 上放置過濾器 ch.addFilter(filter) logger1.addHandler(ch) logger2.addHandler(ch) logger1.error('logger1 error message') logger2.error('logger2 error message') 輸出結果: 2018-11-15 21:58:33,409 - a.b.c - ERROR - logger1 error message
能夠看到 logger2 被過濾,只有 logger1 輸出日誌~
在 handler 上添加 filter:
import logging logger1 = logging.getLogger('a.b.c') logger2 = logging.getLogger('a.c') # 定義一個 filter filter = logging.Filter(name='a.b') # 定義一個 handler ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter) # 若兩個 logger對象 的日誌級別相同,且都是用經過一個 handler,能夠在這個 handler 上設置日誌級別 ch.setLevel(logging.ERROR) # 在 logger 上放置過濾器 logger1.addFilter(filter) logger2.addFilter(filter) logger1.addHandler(ch) logger2.addHandler(ch) logger1.error('logger1 error message') logger2.error('logger2 error message')
輸出結果一致,即僅有 logger1 輸出日誌。將 filter 添加到 logger 上,這個filter將直接做用於這個 logger,貌似這麼意義不大,不多這樣使用
.................^_^