測試環境為 CentOS 8 x86_64 (虛擬機)
參考文章 – https://editor.leonh.space/2022/python-log/ 與 https://iter01.com/578914.html
透過 print 函數可以把執行 python 的訊息顯示在文字命令列上, 如果要把資料導向到檔案或是同時 顯示在文字命令列 並儲存到檔案 這時候可以透過 logging 類別來完成.
使用 logging 類別,有以下 6 個物件.
Logger <- Handler <- Formatter | | <<<<<<<<<<<<<< Filter
- Logger (紀錄器) – 用來執行日誌紀錄,透過 logging.getLogger(name=None) 來生成 .
- Handler (處理器) – 選擇日誌的輸出地方,常用的 Handler ,生成後透過 logger.addHandler(hdlr) 把 Handler 加到 Logger .
- StreamHandler – 透過 logging.StreamHandler(stream=None) 來生成, 將資料輸出到標準輸出 sys.stdout, sys.stderr 或是 file-like object .
- FileHandler – 透過 logging.FileHandler(filename, mode=’a’, encoding=None, delay=False, errors=None) 來生成 ,將資料儲存成檔案.
- Formatter (格式器) – 顯示訊息的格式, 透過 logging.Formatter(fmt=None, datefmt=None, style=’%’, validate=True, *, defaults=None)來生成, 生成後透過 Handler.setFormatter(fmt) 把 Formatter 加到 Handler .
- Filter (過濾器) – 用來控制訊息的輸出內容,看是要加到 logger 或是 Handler ,當你要所有的 Handler 都使用相同的 Filter 時就在 logger 物件透過 logger.addFilter(filter) 來生成 ,想要在個別 Handler 使用時就在 Handler 物件透過 handler.addFilter(filter) 來生成 .
- LogRecord – 產生 Logger 時自動生成.
- LoggerAdapter – 沒使用過.
使用以下範例來看一下這幾個物件的使用.
- 範例 : 生成 Logger 的用法
[root@localhost ~]# vi logger.py import logging logger = logging.getLogger(__name__) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
執行結果
[root@localhost ~]# python3 logger.py warning message error message critical message
說明:
匯入 logging 套件.import logging
透過 logging.getLogger 建立屬於自己的 logging instance (這樣可以使用自己設定的組態,可依據需求將執行結果儲存到不同的檔案,並賦予不同的輸出格式),我們也是可以直接使用 logging 但會影響到 root 的 logging 的設定.
帶入參數使用 __name__ 使用在模組時 Formatter 的 %(name)s 顯示其模組名稱.
logger = logging.getLogger(__name__)
透過建立好的 logger 來產生 不同 等級的訊息.預設等級大於 WARNING ,以上的訊息才會被記錄起來,等級如下:
NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICALlogger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
結果
warning message error message critical message
- 範例 : 生成 handler + setLevel 的用法
[root@localhost ~]# vi handler.py import logging logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) handler = logging.StreamHandler() logger.addHandler(handler) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
執行結果
[root@localhost ~]# python3 handler.py debug message info message warning message error message critical message
說明:
logging 類別預設要等級大於 WARNING ,以上的訊息才會被記錄起來,等級如下:
NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL把預設的 WARNING 設定變更為 Debug 以上皆會紀錄.
logger.setLevel(logging.DEBUG)
除了剛剛建立好的 logger 我們還需要透過 logging.StreamHandler 建立 handler ,該類別主要負責訊息的輸出到 sys.stdout, sys.stderr 或是 file-like object (支援 write() 與 flush() 的 methods ) .
handler = logging.StreamHandler()
生成後透過 logger.addHandler(hdlr) 把 Handler 加到 Logger .我們可以透過定義多個 handler (後面範例) 來讓訊息同時顯示在 文字命令列 並儲存到檔案裡面.
logger.addHandler(handler)
- 範例 : 生成 formatter 來變更改資料輸出格式的用法
[root@localhost ~]# vi formatter.py import logging logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) handler = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
執行結果
[root@localhost ~]# python3 lformatter.py 2022-05-25 23:36:48,078 - __main__ - DEBUG - debug message 2022-05-25 23:36:48,078 - __main__ - INFO - info message 2022-05-25 23:36:48,078 - __main__ - WARNING - warning message 2022-05-25 23:36:48,078 - __main__ - ERROR - error message 2022-05-25 23:36:48,078 - __main__ - CRITICAL - critical message
說明:
透過 logging.Formatter(fmt=None, datefmt=None, style=’%’, validate=True, *, defaults=None)來生成,各式格式請參考說明 – https://docs.python.org/3/library/logging.html#logrecord-attributesformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
生成後透過 Handler.setFormatter(fmt) 把 Formatter 加到 Handler .
handler.setFormatter(formatter)
- 範例 : 生成 handler 來變更改資料輸出到檔案的用法
[root@localhost ~]# vi FileHandler.py import logging logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) handler = logging.FileHandler('filehandler.log') formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
執行結果
[root@localhost ~]# python3 FileHandler.py
[root@localhost ~]# cat filehandler.log 2022-05-31 13:24:41,336 - __main__ - DEBUG - debug message 2022-05-31 13:24:41,336 - __main__ - INFO - info message 2022-05-31 13:24:41,336 - __main__ - WARNING - warning message 2022-05-31 13:24:41,336 - __main__ - ERROR - error message 2022-05-31 13:24:41,336 - __main__ - CRITICAL - critical message
說明:
透過 logging.FileHandler(filename, mode=’a’, encoding=None, delay=False, errors=None) 來生成 ,將資料儲存成檔案.handler = logging.FileHandler('filehandler.log')
- 範例 : 生成不同 handler 來讓資料同時輸出到文字命令列與檔案的方法
[root@localhost ~]# vi 2handler.py import logging logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) handler1 = logging.FileHandler('2handler.log') handler2 = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler1.setFormatter(formatter) handler2.setFormatter(formatter) logger.addHandler(handler1) logger.addHandler(handler2) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
執行結果
[root@localhost ~]# python3 2handler.py 2022-05-31 13:26:59,835 - __main__ - DEBUG - debug message 2022-05-31 13:26:59,835 - __main__ - INFO - info message 2022-05-31 13:26:59,835 - __main__ - WARNING - warning message 2022-05-31 13:26:59,835 - __main__ - ERROR - error message 2022-05-31 13:26:59,836 - __main__ - CRITICAL - critical message
[root@localhost ~]# cat 2handler.log 2022-05-31 13:26:59,835 - __main__ - DEBUG - debug message 2022-05-31 13:26:59,835 - __main__ - INFO - info message 2022-05-31 13:26:59,835 - __main__ - WARNING - warning message 2022-05-31 13:26:59,835 - __main__ - ERROR - error message 2022-05-31 13:26:59,836 - __main__ - CRITICAL - critical message
說明:
生成 2 個,一個 handler 指向 文字命令列 另外一個指向 檔案(使用相同的格式 formatter).handler1 = logging.FileHandler('2handler.log') handler2 = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler1.setFormatter(formatter) handler2.setFormatter(formatter) logger.addHandler(handler1) logger.addHandler(handler2)