1、概括理解
瞭解了四大元件的基本定義之後,我們通過圖示的方式來理解下資訊的傳遞過程:
也就是獲取的日誌資訊,進入到Logger日誌器中,傳遞給處理器確定要輸出到哪裡,然後進行過濾器篩選,通過後再按照定義的格式進行日誌的輸出。
2、詳細說明
描述上面這個圖的日誌流處理流程:
- 1)在使用者程式碼中進行日誌記錄函式呼叫,如:
logger.info(…)
,logger.debug(…)
等; - 2)判斷要記錄的日誌級別是否滿足日誌器設定的級別要求。
要記錄的日誌級別要大於或等於日誌器設定的級別才算滿足要求,如果不滿足則該日誌記錄會被丟棄,並終止後續的操作,如果滿足則繼續下一步操作; - 3)根據日誌記錄函式呼叫時傳入的引數,建立一個日誌記錄(
LogRecord
類)物件; - 4)判斷日誌記錄器上設定的過濾器是否拒絕這條日誌記錄,如果日誌記錄器上的某個過濾器拒絕,則該日誌記錄會被丟棄並終止後續的操作。如果日誌記錄器上設定的過濾器,不拒絕這條日誌記錄,或者日誌記錄器上沒有設定過濾器,則繼續下一步操作,將日誌記錄分別交給該日誌器上新增的各個處理器;
- 5)判斷要記錄的日誌級別是否滿足處理器設定的級別要求。
要記錄的日誌級別要大於或等於該處理器設定的日誌級別才算滿足要求,如果不滿足記錄將會被該處理器丟棄並終止後續的操作,如果滿足則繼續下一步操作; - 6)判斷該處理器上設定的過濾器是否拒絕這條日誌記錄,如果該處理器上的某個過濾器拒絕,則該日誌記錄會被當前處理器丟棄並終止後續的操作。如果當前處理器上設定的過濾器不拒絕這條日誌記錄,或當前處理器上沒有設定過濾器測繼續下一步操作;
- 7)如果能到這一步,說明這條日誌記錄經過了層層關卡允許被輸出了,此時當前處理器會根據自身被設定的格式器(如果沒有設定則使用預設格式),會將這條日誌記錄進行格式化,最後將格式化後的結果,輸出到指定位置(檔案、網路、類檔案的
Stream
等); - 8)如果日誌器被設定了多個處理器的話,上面的第5-8步會執行多次;
- 9)這裡才是完整流程的最後一步:判斷該日誌器輸出的日誌訊息是否需要傳遞給上一級
logger
。
日誌器是有層級關係的,如果propagate
屬性值為1,則表示日誌訊息將會被輸出到處理器指定的位置,同時還會被傳遞給parent
日誌器的handlers
進行處理,直到當前日誌器的propagate
屬性為0停止,如果propagate
值為0則表示不向parent
日誌器的handlers
傳遞該訊息,到此結束。
可見,一條日誌資訊要想被最終輸出需要依次經過以下幾次過濾:
- 日誌器等級過濾;
- 日誌器的過濾器過濾;
- 日誌器的處理器等級過濾;
- 日誌器的處理器的過濾器過濾;
3、應用示例
(1)需求:
- 1)要求將所有級別的所有日誌都寫入磁碟檔案中
- 2)
all.log
檔案中記錄所有的日誌資訊,日誌格式為:日期和時間 - 日誌級別 - 日誌資訊
。 - 3)
error.log
檔案中單獨記錄error
及以上級別的日誌資訊,日誌格式為:日期和時間 - 日誌級別 - 檔名[:行號] - 日誌資訊
。 - 4)要求
all.log
在每天凌晨進行日誌切割。
(2)分析:
- 1)要記錄所有級別的日誌,因此日誌器的有效
level
需要設定為最低階別DEBUG; - 2)日誌需要被髮送到兩個不同的目的地,因此需要為日誌器設定兩個
handler
;
另外,兩個目的地都是磁碟檔案,因此這兩個handler
都是與FileHandler
相關的; - 3)
all.log
要求按照時間進行日誌切割,因此他需要用logging.handlers.TimedRotatingFileHandler
類;
而error.log
沒有要求日誌切割,因此可以使用FileHandler
類; - 4)兩個日誌檔案的格式不同,因此需要對這兩個
handler
分別設定格式器;
(3)示例
# 匯入logging模組
import logging
import logging.handlers
# 或者 from logging.handlers import TimedRotatingFileHandler
import datetime
# 建立一個日誌器,就是一個logger物件
logger = logging.getLogger('logger')
# 設定logger日誌級別
logger.setLevel(logging.DEBUG)
# 定義處理器1
# 這裡進行簡化
# rf_handler = logging.handlers.TimedRotatingFileHandler('all.log', when='midnight', interval=1, backupCount=7,
# atTime=datetime.time(0, 0, 0, 0))
"""
`TimedRotatingFileHandler`位於`logging.handlers`模組中,
支援按一定時間間隔更換磁碟日誌檔案。這樣就可以保證日誌單個檔案不會太大。
可以根據官方文件自己學習:
https://docs.python.org/zh-cn/3/library/logging.handlers.html
"""
all_handler = logging.FileHandler('../log/all.log', encoding="utf-8")
# 給處理器傳入格式器
all_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
# 定義處理器2
error_handler = logging.FileHandler('../log/error.log', encoding="utf-8")
# 設定處理器日誌級別
error_handler.setLevel(logging.ERROR)
# 給處理器傳入格式器
error_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s"))
# 把兩個處理器新增到日誌器中
logger.addHandler(all_handler)
logger.addHandler(error_handler)
logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')
logger.critical('critical message')
執行結果:
all.log
檔案輸出。
2021-01-15 23:12:27,197 - DEBUG - debug message
2021-01-15 23:12:27,198 - INFO - info message
2021-01-15 23:12:27,198 - WARNING - warning message
2021-01-15 23:12:27,198 - ERROR - error message
2021-01-15 23:12:27,198 - CRITICAL - critical message
error.log
檔案輸出。
2021-01-15 23:12:27,198 - ERROR - demo_log3.py[:35] - error message
2021-01-15 23:12:27,198 - CRITICAL - demo_log3.py[:36] - critical message
參考:https://blog.csdn.net/mk1843109092/article/details/97104041