Python-logging模塊實現同時向控制台和文件打印日志
前言
在寫我自己的練手項目的時候,需要寫一系列Python腳本來幫助我進行運維/環境配置,我希望這些腳本能夠有比較好的日志記錄。
一方面我希望其能夠直接打印到控制台,方便我實時查看,另一方面我也希望能夠記錄到日志文件中,這樣能夠方便我日后翻舊賬。
更進一步,我希望控制台輸出比較重要的信息,讓我的控制台不至於太亂,而日志文件中我希望能夠盡量詳細。
本博客中,我實現了日志同時向控制台和日志中進行輸出,並且二者的日志等級、日志格式不相同。
參考
basicConfig
參考Python 官方文檔 | logging模塊#basicConfig
這個函數對logging模塊的日志記錄器進行基本配置,無論我們直接通過logging.info(msg)
進行日志記錄,還是我們先通過logging.getLogger(name)
獲取一個logger再進行日志記錄,通過basicConfig
函數加入的配置都會生效。
值得注意的是,因為有些操作會導致basicConfig
函數被自動調用,所以我們盡量在程序開始時盡早進行調用。
我們需要關注的是basicConfig
的handlers
參數。
handler
如果說logger是面向上層開發者的接口,那么handler就是面向底層的執行者。開發者通過調用logger的方法來輸出日志,而logger通過handler將日志進行實際的記錄。
一個logger可以有若干handler,logger和handler都可以有一個日志等級。當記錄等級高於logger的日志時,logger會通知每一個handler對該日志進行記錄,而每一個handler記錄會通過該條日志的等級和handler的等級進行比較,當日志等級高於handler等級的時候,才會進行記錄。
handler主要位於logging.handler包下,我們這次需要使用StreamHandler
以及其子類FileHandler
。
實現
通過前面的分析,思路已經很清晰了:
- 創建兩個handler,其中一個向控制台進行輸出,一個向文件進行輸出;
- 為這兩個handler配置不同的日志等級和日志格式;
- 通過
basicConfig
函數來將這兩個handler添加到全局日志的默認配置;
以下為實現:
import logging
import sys
def config_logging(file_name: str, console_level: int=logging.INFO, file_level: int=logging.DEBUG):
file_handler = logging.FileHandler(file_name, mode='a', encoding="utf8")
file_handler.setFormatter(logging.Formatter(
'%(asctime)s [%(levelname)s] %(module)s.%(lineno)d %(name)s:\t%(message)s'
))
file_handler.setLevel(file_level)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(logging.Formatter(
'[%(asctime)s %(levelname)s] %(message)s',
datefmt="%Y/%m/%d %H:%M:%S"
))
console_handler.setLevel(console_level)
logging.basicConfig(
level=min(console_level, file_level),
handlers=[file_handler, console_handler],
)
if __name__ == '__main__':
config_logging("test.log", logging.WARNING, logging.DEBUG)
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.critical("critical")
logger = logging.getLogger(__name__)
logger.debug("debug")
logger.info("info")
logger.warning("warning")
logger.critical("critical")
關鍵是config_logging
函數,這個函數進行了基本的配置,我們只需要在程序的入口處先調用這個函數就能完成全局的日志配置。
需要注意的是在調用logging.basicConfig
時,我們需要設置level=min(console_level, file_level)
,這是因為這個參數設置的是logger的等級,如果一條日志已經被logger過濾掉了,那么handler的等級設置的再低也不會進行記錄。直接level=logging.DEBUG
、level=0
應該也可以,但是我認為比所有handler的等級都低的日志是不會進行輸出的,與其讓這條日志到了handler這一步才被過濾,不如直接就在logger這一步就將其過濾掉。
關於Formatter相關的操作,請看下一篇博客。