Python 的 logging 模組提供強大的日誌記錄功能,但有效運用格式化和組態技巧才能充分發揮其效用。日期時間格式化是日誌記錄的基礎,利用 strftime 方法能客製化時間戳記格式。引數化日誌訊息則能提升日誌的可讀性和資訊量,使用 %s 等格式化字串搭配變數,讓日誌訊息更具體。logging 模組提供三種組態方式:使用 logging API 直接在程式碼中設定,適合簡單的日誌需求;使用 fileConfig 讀取設定檔,方便管理複雜組態;使用 dictConfig 以字典形式定義組態,兼具靈活性與可讀性。選擇哪種方式取決於專案規模和複雜度。理解這些技巧,才能建構更完善的日誌系統,提升程式碼除錯和系統監控效率。

日誌格式化

日誌格式化是日誌系統中的重要環節,它決定了日誌記錄的呈現方式。無論是用於除錯、監控還是稽核,日誌格式化都能幫助你提取有價值的資訊。本章將探討如何利用 Python 的 logging 模組來格式化日誌,並介紹一些常見的格式化技巧與方法。

日期與時間格式化

日期和時間是日誌中非常重要的一部分,因為它們提供了事件發生的時間戳記。Python 的 datetime 模組提供了豐富的日期和時間格式化功能,你可以根據需要進行自定義。

以下是一些常見的日期和時間格式碼:

  • %Y:四位數年份(例如:2023)
  • %m:兩位數月份(例如:09)
  • %d:兩位數日期(例如:02)
  • %H:兩位數小時(24 小時制)(例如:13)
  • %M:兩位數分鐘(例如:28)
  • %S:兩位數秒鐘(例如:02)

這些格式碼可以組合使用來建立自定義的日期和時間格式。例如:

import datetime

# 取得當前時間
now = datetime.datetime.now()

# 自定義日期和時間格式
formatted_date = now.strftime("%Y-%m-%d %H:%M:%S")
print(formatted_date)

內容解密:

在這段程式碼中,我們使用了 datetime 模組來取得當前的日期和時間,然後使用 strftime 方法來將其轉換為指定的格式。這樣可以方便地將日期和時間記錄到日誌中,供後續分析和查詢使用。

使用引數

在記錄日誌時,你可能會需要傳遞引數以提高日誌的可讀性和資訊量。Python 的 logging 模組支援多種方式來進行字串替換,其中推薦使用 printf 風格的字串替換。

以下是一個示例:

name = "Mike"
print("Nice to meet you, %s" % name)

在這個示例中,我們使用了 %s 作為佔位符,並且在字串後面使用百分號 % 來插入變數 name 的值。

logging 模組中,我們可以這樣使用:

import logging

# 建立自定義日誌記錄器
logger = logging.getLogger(name="test")
logger.setLevel(logging.DEBUG)

# 建立檔案處理器
file_handler = logging.FileHandler("params.log")

# 新增處理器到日誌記錄器
logger.addHandler(file_handler)

# 新增格式化器
formatter = logging.Formatter()
file_handler.setFormatter(formatter)

name = "Mike"
logger.debug("Nice to meet you, %s", name)

內容解密:

這段程式碼展示瞭如何在 Python 中使用 logging 模組來進行字串替換。我們首先建立了一個名為 test 的日誌記錄器並設定其級別為 DEBUG。然後,我們建立了一個檔案處理器並將其新增到日誌記錄器中。接著,我們建立了一個格式化器並設定到檔案處理器上。最後,我們使用字串替換來記錄一條包含變數 name 值的日誌訊息。

日誌組態

Python 的 logging 模組提供了三種主要方法來組態你的日誌系統。那麼什麼是日誌組態呢?簡單地說,日誌組態告訴 Python 的日誌記錄器以下幾點:

  • 日誌應該存放在哪裡(處理器)
  • 日誌訊息應該如何格式化(格式化器)
  • 你希望記錄哪級別的日誌(DEBUG、INFO、CRITICAL 等)
  • 有時還會有一些額外組態

本章將探討這三種不同的組態方法。

組態方法概覽

Python 提供了三種組態方式:

  1. 使用 logging API:透過程式碼直接組態。
  2. 使用 fileConfig:透過讀取組態檔案來組態。
  3. 使用 dictConfig:透過字典來組態。

這些方法為你提供了很大的靈活性。選擇哪種方法取決於你的經驗和專案型別。不必擔心第一次選擇不當,學習新事物時犯錯並改正是很正常的。

組態方式一:使用 logging API

透過程式碼直接組態日誌系統是最直接也最靈活的一種方式。以下是一個示例:

import logging
import time

def main():
    """
    主入口函式
    """
    logger = logging.getLogger("example_app")
    logger.setLevel(logging.INFO)

    # 建立檔案處理器
    file_handler = logging.FileHandler("example.log")
    formatter = logging.Formatter(
        ("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
    file_handler.setFormatter(formatter)

    # 建立控制檯處理器
    stream_handler = logging.StreamHandler()
    stream_formatter = logging.Formatter(
        ("%(asctime)s - %(filename)s - %(lineno)d - %(message)s"))
    stream_handler.setFormatter(stream_formatter)

    # 新增處理器到日誌記錄器
    logger.addHandler(file_handler)
    logger.addHandler(stream_handler)

    logger.info("程式開始")

    # 模擬一些工作
    time.sleep(2)

    logger.info("完成!")

if __name__ == "__main__":
    main()

內容解密:

這段程式碼展示瞭如何透過程式碼直接組態日誌系統。首先,我們建立了一個名為 example_app 的日誌記錄器並設定其級別為 INFO。然後,我們分別建立了一個檔案處理器和一個控制檯處理器,並為它們設定了不同的格式化器。最後,我們將這些處理器新增到日誌記錄器中,並在主函式中進行了一些模擬工作。

組態方式二:使用 fileConfig

透過讀取組態檔案來組態日誌系統也是一種常見的方式。這樣可以將組態資訊與程式碼分離開來,使得維護和修改更加方便。

假設你有一個名為 logging_config.ini 的組態檔案:

[loggers]
keys=root,example_app

[handlers]
keys=fileHandler,streamHandler

[formatters]
keys=defaultFormatter

[logger_root]
level=DEBUG
handlers=fileHandler,streamHandler

[logger_example_app]
level=INFO
handlers=
qualname=example_app

[handler_fileHandler]
class=FileHandler
args=('example.log',)
level=INFO
formatter=defaultFormatter

[handler_streamHandler]
class=StreamHandler
level=INFO
formatter=defaultFormatter

[formatter_defaultFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

然後在你的 Python 程式碼中讀取這個組態檔案:

import logging.config

logging.config.fileConfig('logging_config.ini')

logger = logging.getLogger('example_app')
logger.info('Program started')

# 模擬一些工作
time.sleep(2)

logger.info('Done!')

內容解密:

這段程式碼展示瞭如何透過讀取組態檔案來組態日誌系統。首先,我們使用 logging.config.fileConfig 函式讀取名為 logging_config.ini 的組態檔案。然後,我們取得名為 example_app 的日誌記錄器並進行一些模擬工作。

組態方式三:使用 dictConfig

透過字典來組態日誌系統也是一種靈活且強大的方式。以下是一個示例:

import logging.config

config = {
    'version': 1,
    'formatters': {
        'default': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        }
    },
    'handlers': {
        'file': {
            'class': 'logging.FileHandler',
            'filename': 'example.log',
            'formatter': 'default'
        },
        'stream': {
            'class': 'logging.StreamHandler',
            'formatter': 'default'
        }
    },
    'loggers': {
        'example_app': {
            'handlers': ['file', 'stream'],
            'level': 'INFO'
        }
    }
}

logging.config.dictConfig(config)

logger = logging.getLogger('example_app')
logger.info('Program started')

# 模擬一些工作
time.sleep(2)

logger.info('Done!')

內容解密:

這段程式碼展示瞭如何透過字典來組態日誌系統。首先,我們定義了一個名為 config 的字典,其中包含了各種組態資訊,包括處理器、格式化器和記錄器。然後,我們使用 logging.config.dictConfig 函式載入這些組態資訊。最後,我們取得名為 example_app 的日誌記錄器並進行一些模擬工作。

使用檔案組態Log記錄

在Python中,使用logging模組來進行日誌記錄是非常普遍的做法。這章節將介紹如何使用檔案組態來管理日誌記錄,這樣可以將複雜的組態邏輯從程式碼中分離出來,使程式碼更加簡潔。

組態檔案結構

首先,我們需要了解組態檔案的結構。Python的logging模組支援使用類別似Windows INI組態檔案的格式來進行組態。這種格式由configparser模組來解析,並且它的結構非常簡單。

組態檔案的基本結構

  1. 區段(Section):區段用方括號([])來標示,例如[loggers]
  2. 鍵值對(Key-Value Pair):在區段內,每一行都是一個鍵值對,鍵和值之間用等號(=)分隔。

以下是一個簡單的組態檔案範例:

[loggers]
keys=root,example_app

[handlers]
keys=fileHandler, consoleHandler

[formatters]
keys=file_formatter, stream_formatter

[logger_root]
level=CRITICAL
handlers=consoleHandler

[logger_example_app]
level=INFO
handlers=fileHandler
qualname=example_app

[handler_consoleHandler]
class=StreamHandler
formatter=stream_formatter
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=file_formatter
args=("config.log",)

[formatter_file_formatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

[formatter_stream_formatter]
format=%(asctime)s - %(filename)s - %(lineno)s - %(message)s
datefmt=%a %d %b %Y

詳細解說

段落標題:區段說明

  • loggers:定義所有可用的日誌器。
  • handlers:定義所有可用的處理器。
  • formatters:定義所有可用的格式化器。

次段落標題:日誌器組態

  • logger_root:根日誌器,負責捕捉所有未分配到其他日誌器的日誌記錄。
  • logger_example_app:自定義日誌器,可以用於特定應用程式或模組。

次段落標題:處理器組態

  • handler_consoleHandler:將日誌記錄輸出到控制檯。
  • handler_fileHandler:將日誌記錄寫入到檔案中。

次段落標題:格式化器組態

  • formatter_file_formatter:定義寫入檔案時的日誌格式。
  • formatter_stream_formatter:定義輸出到控制檯時的日誌格式。

使用檔案組態日誌

接下來,我們需要在Python程式碼中載入這個組態檔案並進行日誌記錄。以下是具體步驟:

  1. 建立一個名為logging.conf的組態檔案,內容如上所述。
  2. 建立一個Python檔案,例如log_with_config.py,並新增以下程式碼:
import logging
import logging.config
import time

def main():
    logging.config.fileConfig("logging.conf")
    logger = logging.getLogger("example_app")

    logger.info("Program started")
    time.sleep(3)
    logger.info("Done!")

if __name__ == "__main__":
    main()

#### 內容解密:

在此程式碼中,我們首先匯入了必要的模組,然後在main()函式中使用logging.config.fileConfig()方法來載入組態檔案。接著,我們取得了名為example_app的日誌器並進行了一些基本的日誌記錄操作。

import logging         # 匯入 logging 模組
import logging.config  # 匯入 logging.config 模組以載入組態檔案
import time            # 匯入 time 模組以使用 sleep 函式

def main():
    logging.config.fileConfig("logging.conf")  # 載入組態檔案
    logger = logging.getLogger("example_app")  # 取得名為 example_app 的日誌記錄器

    logger.info("Program started")           # 記錄一條資訊級別的日誌記錄
    time.sleep(3)                          # 暫停3秒以模擬一些工作時間
    logger.info("Done!")                    # 記錄另一條資訊級別的日誌記錄

if __name__ == "__main__":
    main()                                # 執行主函式

當你執行這個程式碼時,你會看到類別似以下的輸出:

2023-10-05 Thu Oct 05 - log_with_config.py - 14 - Program started
2023-10-05 Thu Oct 05 - log_with_config.py - 17 - Done!

同時,你也會在組態檔案中指定的config.log檔案中看到相應的日誌記錄。

視覺化此圖示展示了組態檔案與Python程式碼之間的關係

  graph TD;
    A[config.log] --> B[FileHandler];
    B --> C[FileFormatter];
    D[Console] --> E[StreamHandler];
    E --> F[StreamFormatter];
    G[Logger: example_app] --> B;
    G --> E;

本圖示展示瞭如何從組態檔案中的設定到實際應用於Python程式碼中的過程。每個部分都對應到相應的設定專案和其功能。