Page cover

logging 【日誌】

Logging


Logging library module 允許開發人員將日誌功能整合到他們的應用程序中,從而在運行時記錄事件、錯誤和其他重要信息。

Logging library module
Logging library module

print() 是沒有嚴重性概念的普通文本。而 Logging 具有 4 個級別的日誌訊息嚴重性或重要性,有助於從訊息忽略較低嚴重性的訊息。

Log 級別
說明

info(msg, *args, **kwargs)

監視和理解應用程序行為。(例如: 報告流程、事件、顯示狀態)

debug(msg, *args, **kwargs)

用於開發和測試階段。(例如: 記錄變數值、路徑、內部狀態)

warning(msg, *args, **kwargs)

表示問題已經發生或即將發生,但應用程序仍可以繼續運行。

error(msg, *args, **kwargs)

表示特定操作或任務失敗或遇到異常。錯誤通常會阻止應用程序按預期運行或產生不正確的結果。

critical(msg, *args, **kwargs)

表示對應用程序的功能有重大的嚴重錯誤。當此類事件發生時,應用程序可能處於不穩定或不可恢復的狀態。

PYTHON
import logging

# log
logging.info("[This is a info]") 
logging.warning("[This is a warning]")
logging.error("[This is a error]")
logging.critical("[This is a critical]")

執行結果

WARNING:root:[This is a warning]
ERROR:root:[This is a error]
CRITICAL:root:[This is a critical]

最佳的紀錄工具


任務
工具

顯示在 Terminal

print()

監控或故障調查

logging.info()logging.debug()

發出事件的警告

logging.warning()(注意該事件)、warnings.warn();(必須修正該事件)

報告事件的錯誤

引發 Exception。詳見: [[exception 【異常】]]

抑制錯誤而不引發異常 (例如: 伺服器中的 Threading)

logging.error(), logging.exception(), logging.critical()

basicConfig


快速設定多個屬性 (logger、FileHandler...)

PYTHON
logging.basicConfig(**kwargs)

常用的參數:

輸出級別控制
說明

filename

寫入日誌訊息的檔案名稱,否則輸出在 Terminal。

filemode

寫入模式,即 open()。如果指定 filename,則使用 "a"

format

需要寫入的日誌訊息。詳見: LogRecord attributes

datefmt

指定的日期/時間格式。與 time.strftime() 的格式相同。

style

日誌訊息的格式('%', '{', '$'),預設為%

level

設置根記錄器級別,不會記錄較小的級別的日誌。級別大小為: DEBUG < INFO < WARNING < ERROR < CRITICAL

encoding

編碼模式。常使用 encoding="UTF-8"

fileConfig

fileConfig() 允許使用 Configuration file 設定日誌記錄,而不是透過程式碼的方式定義。 支持的格式有:.ini、.yaml、.json。

透過使用 logging.config.fileConfig(),您可以將日誌記錄設定與您的程式碼分開,從而在不修改代碼本身的情況下更輕鬆地管理。此外,您可以為不同的環境或模塊使用不同的 Configuration file。

PYTHON
logging.config.fileConfig(fname, 
                          defaults=None, 
                          disable_existing_loggers=True, 
                          encoding=None)

Logger


建立 Logger ,可以過濾 log 資訊。

設定 Logger。

PYTHON
logging.getLogger(name=None)
logging.getLogger(loggeyr_1)           # Ex1.
logging.getLogger(logger_1.logger_1_2) # Ex2. 可以使用`.` 代表 Logger 的階層。

Handler


如何處理 Logger 的資訊。

將 Logger 輸出到 File。

logging.FileHandler(filename, 
                    mode='a', 
                    encoding=NoHne, 
                    delay=False, 
                    errors=None)

將 Logger 輸出到 Terminal。

logging.StreamHandler(stream=None)

將 Logger 輸出到 Web 。

PYTHON
handlers.HTTPHandler(host, 
                     url, 
                     method='GET', 
                     secure=False, 
                     credentials=None, 
                     context=None)

設定 Handler 屬性。 其他屬性詳見:logging.Handler

PYTHON
file_handler = logging.FileHandler('app.log')

# =========================================================
# level
file_handler.setLevel(logging.INFO)

# Formatter
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)

Filter


Filter class 允許您自定義過濾器以根據特定條件有選擇地過濾掉日誌記錄。 它提供了一種微調日誌記錄系統中日誌記錄處理的方法。

Filter Filter class 是一個 base class, 它提供了一個 filter(record) 的方法,您需要在子 class 中覆蓋該方法。 filter() 方法將日誌記錄作為輸入,如果返回 True,則處理該日誌;則返回 True,如果返回 False,則跳過該日誌 。

範例


basicConfig

PYTHON
'''basicConfig'''

import logging

# 建立 logger 和 FileHandler
logging.basicConfig(filename = 'log.txt',
                    level = logging.DEBUG,
                    format = '{asctime}: {levelname}: {name}: {message}',
                    style='{')
                    #format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s')

logging.debug('Debug message')
logging.info('Info message')
logging.warning('Warning message')
logging.error('Error message')
logging.critical('Critical message')

執行結果:

執行結果
執行結果
PYTHON
'''
basicConfig ->logger
            ->logger
'''

import logging

# 設定多個屬性
logging.basicConfig(filename='app.log', 
                    level=logging.INFO, 
                    format='%(asctime)s - %(levelname)s - %(message)s')

# =========================================================
# logger 1 
logger = logging.getLogger('my_logger_1')
logger.setLevel(logging.DEBUG)

# log
logger.debug('This is a debug message.')         # ✔️✔️
logger.info('This is an informational message.') # ✔️✔️
logger.warning('This is a warning message.')     # ✔️✔️

# =========================================================
# logger 2
logger_2 = logging.getLogger('my_logger_2') 
logger_2.setLevel(logging.WARNING)

# log
logger_2.debug('This is a debug message.')
logger_2.info('This is an informational message.')
logger_2.warning('This is a warning message.')   # ✔️✔️

執行結果:

app.log
2023-07-19 18:18:20,495 - DEBUG - This is a debug message.
2023-07-19 18:18:20,495 - INFO - This is an informational message.
2023-07-19 18:18:20,495 - WARNING - This is a warning message.
2023-07-19 18:18:20,495 - WARNING - This is a warning message.

fileConfig


INI
[loggers]
keys=root

[handlers]
keys=fileHandler, consoleHandler

[formatters]
keys=defaultFormatter

[logger_root]
level=DEBUG
handlers=fileHandler, consoleHandler

[handler_fileHandler]     # 輸出到 檔案
class=FileHandler
level=DEBUG
formatter=defaultFormatter
args=('example.log', 'a')

[handler_consoleHandler]  # 輸出到 Terminal
class=StreamHandler
level=DEBUG
formatter=defaultFormatter
args=(sys.stdout,)

[formatter_defaultFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S
YAML
version: 1
formatters:
  defaultFormatter:
    format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    datefmt: "%Y-%m-%d %H:%M:%S"
    
handlers:
  fileHandler:         # 輸出到 檔案
    class: logging.FileHandler
    level: DEBUG
    formatter: defaultFormatter
    filename: app.log
  consoleHandler:      # 輸出到 Terminal
    class: logging.StreamHandler
    level: DEBUG
    formatter: defaultFormatter
    stream: ext://sys.stdout
    
loggers:
    root:
        level: DEBUG
        handlers: [fileHandler, consoleHandler]
        propagate: yes
PYTHON
import yaml
import logging
import logging.config

# 載入 configuration_file.conf,建立 logger
logging.config.fileConfig('logging.conf')
logger = logging.getLogger(__name__)

# 寫入 Log
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')

# =========================================================
# 載入 configuration_file.yaml,建立 logger
with open('logging.yaml', 'r') as f:
    config = yaml.safe_load(f.read())
    logging.config.dictConfig(config)
logger = logging.getLogger(__name__)

# 寫入 Log
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')

logger


PYTHON
'''getLogger('my_logger') ->FileHandler'''

import logging

# 建立 logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)

# 建立 FileHandler
file_handler = logging.FileHandler('app.log')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)

# 加入 handler
logger.addHandler(file_handler)

# 寫入 log
logger.info('This is an informational message.')
logger.warning('This is a warning message.')

執行結果:

app.log
2023-07-19 17:58:12,393 - INFO - This is an informational message.
2023-07-19 17:58:12,393 - WARNING - This is a warning message.

PYTHON
'''getLogger(__name__) ->FileHandler'''
import logging

# 建立 logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(name)s - %(asctime)s - %(levelname)s - %(message)s')

# 建立 FileHandler
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.WARNING)
file_handler.setFormatter(formatter)

# 加入 handler
logger.addHandler(file_handler)

# log
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')

執行結果:

app.log
__main__ - 2023-07-19 18:01:14,806 - WARNING - This is a warning message
__main__ - 2023-07-19 18:01:14,806 - ERROR - This is an error message

Handler


PYTHON
import logging

# 設定多個屬性
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')

# =========================================================
# 建立 FileHandler
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)

# =========================================================
# 建立 StreamHandler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(formatter)

# =========================================================
# 加入 handler
logger.addHandler(file_handler)
logger.addHandler(console_handler)

# =========================================================
# 寫入 log
logger.debug('This is a debug message.')
logger.info('This is an informational message.')
logger.warning('This is a warning message.')

執行結果:

2023-07-19 18:04:38,094 - DEBUG - This is a debug message.
2023-07-19 18:04:38,094 - INFO - This is an informational message.
2023-07-19 18:04:38,094 - WARNING - This is a warning message.
app.log
2023-07-19 18:04:38,094 - INFO - This is an informational message.
2023-07-19 18:04:38,094 - WARNING - This is a warning message.

Filter


PYTHON
import logging

class LoggerFilter(logging.Filter):
    def filter(self, record):
        return record.levelno >= logging.WARNING


class HandlerFilter(logging.Filter):
    def filter(self, record):
        if record.msg.find('abc') == -1:
            return True
        return False
        
# 建立 Handler
logger = logging.getLogger('test')
logger.setLevel(logging.INFO)

# 建立 Handler
stream_handler = logging.StreamHandler()
logger.addHandler(stream_handler)

# =========================================================
logger.warning('this is warning-1')    # ✔️✔️
logger.info('this is info-1')          # ✔️✔️

# =========================================================
logger.addFilter(LoggerFilter())
logger.warning('this is warning-2')    # ✔️✔️
logger.info('this is info-2')          # Skip this log

# =========================================================
stream_handler.addFilter(HandlerFilter())
logger.warning('this is warning-3')    # ✔️✔️
logger.info('this is info-3')          # Skip this log
logger.warning('this is warning-abc')  # Skip this log

執行結果:

this is warning-1
this is info-1
this is warning-2
this is warning-3

Logger Decorator


PYTHON
import logging

def logger(func):
    def wrapper(*args, **kwargs):
        logging.info(f"Running \"{func.__name__}\" with arguments {args} and kwargs {kwargs}")
        result = func(*args, **kwargs)
        logging.info(f"{func.__name__} returned {result}")
        return result
    return wrapper

logging.basicConfig(level=logging.INFO)

@logger
def adder(x, y):
    return x + y

print(adder(10, 5))

執行結果:

INFO:root:Running "adder" with arguments (10, 5) and kwargs {}
INFO:root:adder returned 15
15

PYTHON
import logging

class LevelFilter(logging.Filter):
    """
    This is a custom filter class that filters out log messages below certain level.
    """
    def filter(self, record):
        return record.levelno >= logging.INFO

def setup_logger():
    logger = logging.getLogger('custom_logger')
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    # Create console handler with a higher log level
    ch = logging.StreamHandler()
    ch.setLevel(logging.INFO)
    ch.setFormatter(formatter)
    logger.addHandler(ch)

    # Create file handler which logs even debug messages
    fh = logging.FileHandler('log_file.log')
    fh.setLevel(logging.INFO)
    fh.setFormatter(formatter)
    logger.addHandler(fh)
    
    # Add filter to the logger
    logger.addFilter(LevelFilter())
    return logger

logger = setup_logger()

def logger_decorator(func):
    def wrapper(*args, **kwargs):
        logger.info(f"Running \"{func.__name__}\" with arguments {args} and kwargs {kwargs}")
        result = func(*args, **kwargs)
        logger.info(f"{func.__name__} returned {result}")
        return result
    return wrapper

@logger_decorator
def adder(x, y):
    return x + y

print(adder(10, 5))

執行結果:

2023-07-19 18:40:51,589 - custom_logger - INFO - Running "adder" with arguments (10, 5) and kwargs {}
2023-07-19 18:40:51,589 - custom_logger - INFO - adder returned 15
15

參考資料


Python Doc

基礎 Logging 指南 — Python 3.11.3 說明文件

進階日誌教程 — Python 3.11.3 說明文件

日誌操作手冊 — Python 3.11.3 說明檔

logging.basicConfig — Python 3.11.3 說明文件

logging.getLogger — Python 3.11.3 說明文件

handlers — Python 3.11.3 文檔

config.fileConfig — Python 3.11.3 documentation

filter objects

Blog

Logging in Python - MachineLearningMastery.com

Logging in Python ——真正的 Python

Python 日誌記錄基礎:方法教程、示例及更多 - Sematext

在 Python 中登錄 - MachineLearningMastery.com

如何使用logging.Filter? | Python笔记

Python logging 模組之 logging.basicConfig 用法和參數詳解_Sir靜堂的博客-CSDN博客

Python - 日誌 (logging) 模組 | Titangene Blog

Last updated

Was this helpful?