Python 日誌系統是開發過程中不可或缺的工具,能有效追蹤程式執行狀態、記錄錯誤資訊,協助開發者快速定位問題。本文從日誌系統的基本組成開始,逐步介紹日誌級別、處理器、格式化器的設定與應用,並輔以實際程式碼範例,讓讀者能快速上手,建構更完善的日誌管理機制。不同於單純使用 print() 函式,logging 模組提供更彈性的組態選項,例如設定輸出目標、日誌格式、級別篩選等,能更精細地控制日誌資訊的產出。此外,文章也示範如何捕捉異常並記錄堆積疊資訊,幫助開發者更有效地進行除錯。

Python 日誌系統概述

歡迎來到 Python 日誌系統的世界!無論你是程式設計新手還是老手,你可能都曾經見過或與日誌互動過。日誌是原始軟體開發者認為會有助於除錯應用程式的任何資訊。它們通常由時間戳記的資訊訊息和不同等級的錯誤組成。

有些公司要求日誌用於稽核目的,例如誰是最後一個編輯或變更設定或檔案的人。大多數開發者使用日誌來追蹤錯誤。如果你設計你的應用程式正確,你可以使用不同的日誌等級來增加或減少日誌的詳細程度。

以下是你在這本文中將學習到的主題:

  • 日誌等級
  • 日誌處理器
  • 日誌格式化器
  • 日誌記錄物件
  • 濾波器物件
  • 許多日誌範例

最後一項有些模糊,所以這裡提供更多背景。這本文的前半部分將教你所有你需要做的事情來在 Python 中進行日誌記錄。後半部分將像是一本食譜,展示各種程式碼範例,幫助你有效地學習日誌記錄。

誰適合閱讀這本文

你不需要是程式設計師或工程師就能使用這本文,但這樣會有幫助。主要目標是那些想要了解 Python 日誌記錄是什麼以及如何有效使用它的人。如果你瞭解 Python 的基本概念,那麼你會更受益!

關於作者

Mike Driscoll 已經使用 Python 進行程式設計超過十年。當 Mike 不為工作編寫程式時,他會在部落格上寫關於 Python 的文章,並為 Real Python 貢獻內容。他曾為 Packt Publishing 和 No Starch Press 擔任技術審查員。Mike 也寫了幾本文。Mike 還創立了 Teach Me Python,你可以透過他的書籍和課程學習 Python 程式語言。

你可以在他的網站上檢視 Mike 的所有書籍清單。Mike 經常在 X(前身為 Twitter)上發布關於 Python、寫作和其他主題的文章。你可以在 @driscollis 處關注他。

本文約定

大多數技術書籍都包含某些型別的約定。這本文的主要約定是程式碼區塊,可能或可能不包含語法高亮顯示。

例如:

my_string = "歡迎來到 Python 日誌記錄!"

這些範例允許你從書籍中直接複製和貼上程式碼。然而,如果你在這樣做時遇到任何問題,下一節將告訴你如何下載程式碼範例。

本文原始碼

如果你需要取得本文中的一些程式碼副本,只需前往書籍的 GitHub 資源函式庫:

讀者反饋

玄貓歡迎對我寫作的反饋。如果你想告訴我你對這本文的看法,可以將意見寄送到以下地址:

錯誤更正

玄貓試圖避免在寫作中發布錯誤,但偶爾會發生。如果你發現這本文中的錯誤,請隨時告訴玄貓,透過以下郵件地址聯絡:

現在,讓我們開始學習吧!

第一章 - 日誌系統入門

當你是初學者並且除錯程式碼時,你可能會使用 Python 的方便 print() 函式。沒有問題。以這種方式使用 print() 是正常的。然而,當你將程式碼推播到生產環境或在 GitHub 上分享它時,應該移除那些 print() 函式。

為什麼?問題在於你可能會意外洩露敏感資訊。例如,有時候會列印 API 金鑰或密碼。當使用 print() 時,它會輸出到標準輸出(stdout),而這些可以被任何執行該程式碼的人看到。不應該與所有人分享這些東西。畢竟,有人可能會登入到您的帳戶。

當然,當使用日誌記錄時,您也不希望記錄公司的密碼或 API 金鑰。任何存取該日誌的人都可能竊取這些憑證並用於不法目的。

您的日誌有助於追蹤程式進度並修復失敗時進行修復。日誌也用作稽核機制。

在本章中,您將學習以下內容:

  • 日誌是什麼
  • 他們為什麼有用
  • print() vs. 日誌記錄
  • 如何建立簡單的「Hello World」日誌

讓我們開始吧!

什麼是日誌?

日誌是人類可讀取的文字檔案。有時候,您可能會遇到不同格式的檔案,但在 99% 的情況下,它們都是以 .log 副檔名結尾的檔案。大多數日誌檔案在每行的開始都有一個時間戳記。

以下是一個範例日誌訊息:

2023-08-02 15:37:40,592 - exampleApp - INFO - Program started

此日誌訊息有四個部分:

  1. 時間戳記
  2. 應用程式名稱
  3. 日誌等級(參見第二章)
  4. 日誌訊息

您將花費大部分時間學習這些部分以及如何建立它們和新增/移除不同部分。

日誌為何有用?

日誌對以下原因有用:

  1. 認識錯誤路徑
  2. 追蹤程式碼路徑
  3. 稽核
  4. 傳遞根本原因分析
  5. 儲存錯誤報告

上面提到的大多數專案與解決應用程式如何執行以及出了什麼問題相關。稽核屬於企業領域並且可能需要出於治理或認證目的而存在。

Python 使得透過使用 print() 函式來“登記”您正在執行什麼變得很容易。 然而使用 print() 有幾個問題:

  1. print() 預設情況下寫入標準輸出。
  2. print() 沒有時間戳記或其他內建於登記中的便利功能。
  3. print() 沒有詳細程度控制。

Python 的解決方案是 logging 模組提供給 Python 的標準函式庫。

如何建立簡單「Hello World」日誌?

如何使用 Python 建立日誌?感謝您提出這個問題!您只需少量行程式碼即可學習如何建立一個!

開啟您最喜歡的 Python IDE 或文字編輯器並建立名為 hello_log.py 的檔案。然後輸入以下程式碼:

# hello_log.py

import logging

logging.basicConfig(filename="hello.log", level=logging.INFO)

logging.debug("Hello debug")
logging.info("Hello info")
logging.error("Hello error!!!")

內容解密:

  1. 匯入 logging 模組:首先需要匯入 logging 模組。

    import logging
    

    此行程式碼匯入了 logging 模組,使我們能夠使用它來進行日誌記錄操作。

  2. 組態基本日誌設定:使用 logging.basicConfig 函式設定基本組態。

    logging.basicConfig(filename="hello.log", level=logging.INFO)
    
    • filename="hello.log":指定輸出到名為 hello.log 的檔案。
    • level=logging.INFO:設定最低日誌等級為 INFO ,即只顯示 INFO 級別及以上(包括 WARNING, ERROR, 和 CRITICAL)的日誌資訊。
  3. 建立不同等級的日誌資訊:分別建立 DEBUG, INFO, 和 ERROR 三種等級的日誌資訊。

    logging.debug("Hello debug")
    logging.info("Hello info")
    logging.error("Hello error!!!")
    
    • logging.debug("Hello debug"):建立一條 DEBUG 級別的日誌資訊,「Hello debug」,但由於設定最低等級為 INFO ,所以此條訊息不會被寫入檔案。
    • logging.info("Hello info"):建立一條 INFO 級別的日誌資訊,「Hello info」。
    • logging.error("Hello error!!!"):建立一條 ERROR 級別的日誌資訊,「Hello error!!!」。

這段程式碼展示瞭如何透過簡單步驟設定和生成基本的 Python 日誌系統。透過調整組態選項和增加更多複雜性操作可以實作更高效且靈活地管理應用程式中的各種日誌需求。

日誌系統的基本介紹

在這一章中,我們將探討日誌系統的基本概念及其應用。日誌系統是軟體開發中不可或缺的一部分,能夠幫助我們追蹤程式執行過程中的各種事件和錯誤,從而更容易地進行除錯和維護。以下我們將逐步介紹如何使用 Python 的 logging 模組來建立和管理日誌。

首先,我們需要匯入 Python 的 logging 模組並使用 basicConfig() 函式來設定日誌組態。這裡我們可以指定日誌檔案的位置,無論是絕對路徑還是相對路徑。此外,我們還可以設定日誌的級別,這部分內容將在下一章節中詳細講解。目前,我們將日誌級別設定為 INFO 以便演示。

以下是一段簡單的日誌建立範例:

import logging
logging.basicConfig(filename='hello.log', level=logging.INFO)
logging.debug('Hello debug')
logging.info('Hello info')
logging.error('Hello error!!!')

內容解密:

上述程式碼片段的作用如下:

  1. 匯入 logging 模組:這是 Python 自帶的日誌模組,用於記錄程式執行過程中的事件。
  2. 設定日誌組態:使用 basicConfig() 函式來組態日誌的基本引數。這裡我們指定了日誌檔名為 hello.log,並將日誌級別設定為 INFO
  3. 傳送不同級別的日誌訊息:分別發送了 debuginfoerror 級別的日誌訊息。

當我們執行這段程式碼時,會在與 hello_log.py 同一目錄下建立一個名為 hello.log 的檔案。如果我們開啟這個日誌檔案,會看到以下內容:

INFO:root:Hello info
ERROR:root:Hello error!!!

日誌級別

你可能會注意到只有兩行輸出,而非三行。這是因為我們設定的日誌級別為 INFO,這意味著任何低於 INFO 級別的日誌訊息(如 debug)都會被排除。只有 INFO 及以長官別的訊息才會被記錄到檔案中。

在本章中,我們僅需瞭解日誌級別的基本概念。在下一章節中,我們將探討不同日誌級別之間的優先順序和應用場景。

日誌與 print() 的差異

與使用 print() 函式相比,使用 logging 模組有許多優點:

  1. 可組態性強:可以輕鬆地設定不同的日誌級別、格式和輸出目標(如檔案、控制檯等)。
  2. 可擴充套件性好:可以方便地擴充套件到多執行緒或分散式系統中。
  3. 更強大的錯誤處理:可以記錄異常堆積疊資訊,幫助開發者更容易地追蹤和解決問題。

日誌級別探討

在上一章節中,我們簡要介紹了日誌系統及其基礎組態。本章節將探討不同級別的日誌以及如何使用它們來控制記錄資訊量級。

可用的日誌級別

Python 的 logging 模組內建了六種不同級別的日誌記錄:

  1. NOTSET (0) - 表示祖先記錄器應被諮詢以確定記錄級別或所有事件都被記錄(預設設定)
  2. DEBUG (10) - 提供詳細資訊,對於開發除錯很有幫助
  3. INFO (20) - 確認應用程式正常工作
  4. WARNING (30) - 提示意外發生或即將發生問題(例如磁碟空間不足)
  5. ERROR (40) - 應用程式無法正常工作
  6. CRITICAL (50) - 應用程式嚴重錯誤且可能已停止執行
  graph TD;
    A[NOTSET] --> B[DEBUG];
    B --> C[INFO];
    C --> D[WARNING];
    D --> E[ERROR];
    E --> F[CRITICAL];

每個級別都對應一個數值,如果你不打算建立自定義級別則無需關心這些數值。但如果你需要定義自定義級別時則需要注意不要與現有級別衝突。

使用不同級別的示例

現在我們來看一個實際應用示例來瞭解如何使用不同級別記錄資訊。

import logging
logging.basicConfig(filename="log_levels.log", level=logging.DEBUG)

logging.debug("Hello debug")
logging.info("Hello info")
logging.warning("Hello warning")
logging.error("Hello error")
logging.critical("Hello critical!")

內容解密:

  1. 匯入並組態 logging 模組:我們指定了輸出檔案為“log_levels.log”,並且設定了最低記錄級別為 DEBUG。
  2. 記錄不同級別資訊:透過呼叫 logging 物件相應方法記錄了 DEBUG、INFO、WARNING、ERROR 和 CRITICAL 級別資訊。

當我們執行上述程式碼時將得到以下輸出:

DEBUG:root:Hello debug
INFO:root:Hello info
WARNING:root:Hello warning
ERROR:root:Hello error
CRITICAL:root:Hello critical!

改變記錄級別

我們可以透過修改 level 引數來控制哪些級別資訊被記錄。例如:

import logging
logging.basicConfig(filename="log_levels.log", level=logging.WARNING)

logging.debug("Hello debug")
logging.info("Hello info")
logging.warning("Hello warning")
logging.error("Hello error")
logging.critical("Hello critical!")

內容解密:

當我們將 level 引數設定為 WARNING 時:

  • DEBUG 和 INFO 級別資訊將不會被記錄。
  • WARNING、ERROR 和 CRITICAL 級別資訊會被正常記錄。

因此最終輸出結果如下:

WARNING:root:Hello warning
ERROR:root:Hello error
CRITICAL:root:Hello critical!

透過這種方式控制哪些資訊應該被記錄有助於確保我們只保留必要且相關性高度關鍵點內容來簡化後續分析與處理過程。

捕捉異常並記錄

除了簡單記錄訊息之外,還可以透過捕捉異常並使用 logging.exception() 取得詳細堆積疊跟蹤資訊來幫助除錯問題。舉個例子:

import logging

logger = logging.getLogger("excepter")
logger.setLevel(logging.INFO)

def divide(a, b):
    try:
        result = a / b
    except ZeroDivisionError:
        logger.exception("An error has occurred!")
    except TypeError:
        logger.exception("Incompatible types!")
    else:
        return result

if __name__ == "__main__":
    divide(1, 0)

內容解密:

  1. 初始化 logger 物件:我們建立了一個名為“excepter”的logger物件並且設定其最低記錄級別為 INFO。
  2. 捕捉異常並呼叫 logger.exception():在divide函式中嘗試進行除法運算時可能會丟擲兩種異常:ZeroDivisionError 和 TypeError。當這些異常發生時會呼叫 logger.exception() 取得完整堆積疊跟蹤資訊並記錄到檔案中。

當我們執行這個程式碼時就會看到零除錯誤產生時會有詳細堆積疊追蹤資訊被輸出到終端或控制檯上。

透過這些示例演示如何利用 Python 的 logging 模組來控制與管理您應用中的各種日誌訊息並確保它能夠幫助您高效進行除錯與問題排查工作流程!