[python] Python日誌記錄庫loguru使用指北

落痕的寒假發表於2024-06-30

Loguru是一個功能強大且易於使用的開源Python日誌記錄庫。它建立在Python標準庫中的logging模組之上,並提供了更加簡潔直觀、功能豐富的介面。Logging模組的使用見:Python日誌記錄庫logging總結。Loguru官方倉庫見:loguru,loguru官方文件見: loguru-doc

Loguru的主要特點包括:

  • 簡單易用:無需複雜的配置和定製即可實現基本的日誌記錄和輸出。
  • 靈活的日誌格式:支援自定義日誌格式,並提供豐富的格式化選項。
  • 豐富的日誌級別:支援多種日誌級別,例如DEBUG、INFO、WARNING、ERROR和CRITICAL。
  • 多種日誌目標:可以將日誌輸出到終端、檔案、電子郵件、網路伺服器等目標。
  • 強大的日誌處理功能:支援日誌過濾、格式化、壓縮、旋轉等功能。
  • 支援非同步日誌記錄:能夠極大地提升日誌記錄的效能。
  • 支援跨程序、跨執行緒的日誌記錄:可以安全地記錄多程序、多執行緒應用程式的日誌。

Loguru與logging是Python中常用的兩個日誌記錄庫,但兩者在功能和易用性方面存在一些差異,如下所示:

特性 Loguru logging
易用性 更簡單易用 相對複雜
日誌格式 更靈活 較簡單
日誌級別 更豐富 較少
日誌目標 更多種類 較少
日誌處理功能 更強大 較弱
非同步日誌記錄 支援 不支援
跨程序、跨執行緒支援 支援 支援

總的來說,loguru在易用性、功能性和效能方面都優於logging。如果要一個簡單、強大且易於使用的日誌系統,loguru是一個很好的選擇。而如果只是需要快速輸出一些除錯資訊,print可能就足夠了。不過,對於生產環境,使用loguru或其他日誌系統通常會更加合適。

Loguru安裝命令如下:

pip install loguru

# 檢視loguru版本
import loguru
print(loguru.__version__) # 輸出:0.7.2

目錄
  • 1 使用說明
    • 1.1 基礎用法
    • 1.2 日誌配置
    • 1.3 進階使用
  • 2 參考

1 使用說明

1.1 基礎用法

簡單使用

Loguru的核心概念是隻有一個全域性的日誌記錄器,也就是logger。這個設計使得日誌記錄變得非常簡潔和一致。使用Loguru時,你不需要建立多個日誌例項,而是直接使用這個全域性的logger來記錄資訊。這不僅減少了配置的複雜性,也使得日誌管理更加集中和高效。

from loguru import logger

logger.debug("這是一個除錯資訊")

輸出:

2024-06-29 19:57:44.506 | DEBUG    | __main__:<module>:3 - 這是一個除錯資訊

Loguru日誌輸出預設格式如下:

  1. 時間戳:表示日誌記錄的具體時間,格式通常為年-月-日 時:分:秒.毫秒。
  2. 日誌級別:表示這條日誌的嚴重性級別。
  3. 程序或執行緒標識:表示日誌來自哪個模組或指令碼。 __main__ 表示日誌來自主模組。如果是其他檔案會顯示檔名。
  4. 檔名和行號:記錄日誌訊息的函式名和行號。
  5. 日誌訊息:實際的日誌內容,此外loguru支援使用顏色來區分不同的日誌級別,使得日誌輸出更加直觀.

日誌等級

Loguru可以透過簡單的函式呼叫來記錄不同級別的日誌,並自動處理日誌的格式化和輸出。這一特點可以讓使用者專注於記錄重要的資訊,而不必關心日誌的具體實現細節。Loguru支援的日誌級別,按照從最低到最高嚴重性排序:

  • TRACE: 最詳細的日誌資訊,用於追蹤程式碼執行過程。Loguru預設情況下使用DEBUG級別作為最低日誌記錄級別,而不是TRACE級別。這是因為TRACE級別會產生大量的日誌資訊。
  • DEBUG: 用於記錄詳細的除錯資訊,通常只在開發過程中使用,以幫助診斷問題。
  • INFO: 用於記錄常規資訊,比如程式的正常執行狀態或一些關鍵的操作。
  • SUCCESS: 通常用於記錄操作成功的訊息,比如任務完成或資料成功儲存。
  • WARNING: 用於記錄可能不是錯誤,但需要注意或可能在未來導致問題的事件。
  • ERROR: 用於記錄錯誤,這些錯誤可能會影響程式的某些功能,但通常不會導致程式完全停止。
  • CRITICAL: 用於記錄非常嚴重的錯誤,這些錯誤可能會導致程式完全停止或資料丟失。
from loguru import logger

logger.debug("這是一條跟蹤訊息")
logger.debug("這是一條除錯資訊")
logger.info("這是一條普通訊息")
logger.success("操作成功完成")
logger.warning("這是一條警告資訊")
logger.error("這是一條錯誤資訊")
logger.critical("這是一條嚴重錯誤資訊")

輸出:

2024-06-29 19:58:11.535 | DEBUG    | __main__:<module>:3 - 這是一條跟蹤訊息
2024-06-29 19:58:11.536 | DEBUG    | __main__:<module>:4 - 這是一條除錯資訊
2024-06-29 19:58:11.536 | INFO     | __main__:<module>:5 - 這是一條普通訊息
2024-06-29 19:58:11.537 | SUCCESS  | __main__:<module>:6 - 操作成功完成
2024-06-29 19:58:11.537 | WARNING  | __main__:<module>:7 - 這是一條警告資訊
2024-06-29 19:58:11.538 | ERROR    | __main__:<module>:8 - 這是一條錯誤資訊
2024-06-29 19:58:11.538 | CRITICAL | __main__:<module>:9 - 這是一條嚴重錯誤資訊

1.2 日誌配置

在loguru中,add函式用於新增日誌處理器。這個函式用於指定日誌訊息應該被髮送到何處,例如控制檯、檔案或其他自定義的目的地。add函式主要引數介紹如下:

  • sink: 定義日誌訊息的輸出位置,可以是檔案路徑、標準輸出(stdout)、標準錯誤(stderr,預設)或其他自定義的輸出位置。
  • format: 指定日誌訊息的格式,可以是簡單的字串,也可以是格式化字串,支援各種欄位插值。
  • level: 設定處理程式處理的日誌訊息的最低階別。比如設定為DEBUG,則處理程式將處理所有級別的日誌訊息。
  • filter: 可選引數,用於新增過濾器,根據特定的條件過濾掉不需要的日誌訊息。
  • colorize: 布林值,指定是否對日誌訊息進行著色處理,使日誌在控制檯中更易於區分。
  • serialize: 布林值,指定是否對日誌訊息進行序列化處理,通常與enqueue=True一起使用,以確保多執行緒安全。
  • enqueue: 布林值,指定是否將日誌訊息放入佇列中處理,用於多執行緒應用中避免阻塞。
  • backtrace: 布林值或字串,指定是否記錄回溯資訊,預設為False
  • diagnose: 布林值,啟用後,會在處理程式內部出現錯誤時記錄診斷資訊。
  • rotation: 日誌檔案輪換的配置,支援按大小或時間進行日誌檔案的輪換。
  • retention: 用於設定日誌檔案的保留時間。
  • compression: 布林值,指定是否對輪換後的日誌檔案進行壓縮處理。
from loguru import logger
import sys

# 終端顯示不受該段程式碼設定
# 新增一個日誌處理器,輸出到檔案
# 設定日誌最低顯示級別為INFO,format將設定sink中的內容
# sink連結的本地檔案,如不存在則新建。如果存在則追寫
logger.add(sink="myapp.log", level="INFO", format="{time:HH:mm:ss}  | {message}| {level}")

# debug結果不被顯示到本地檔案
logger.debug("這是一條除錯資訊")
logger.info("這是一條普通訊息")

輸出:

2024-06-29 19:58:56.159 | DEBUG    | __main__:<module>:11 - 這是一條除錯資訊
2024-06-29 19:58:56.159 | INFO     | __main__:<module>:12 - 這是一條普通訊息

當連續兩次呼叫 add 函式時,loguru 會將新的日誌處理器新增到處理器列表中,而不是覆蓋之前的處理器。這意味著所有新增的處理器都會接收到日誌訊息,並且按照它們被新增的順序來處理這些訊息。

from loguru import logger
logger.add(sink="myapp1.log", level="INFO")
logger.add(sink="myapp2.log", level="INFO")
# 會同時存入所有add新增日誌處理器
logger.info("這是一條普通訊息,存入myapp2")

如果想刪除所有已新增的日誌處理器,loguru執行使用 logger.remove()方法不帶任何引數來移除所有日誌處理器。

from loguru import logger
import sys

# 移除所有日誌處理器(包括終端輸出)
logger.remove()
logger.add(sink="myapp3.log", level="INFO", format="{time:HH:mm:ss}  | {message}| {level}")

logger.debug("這是一條除錯資訊存入myapp3")
logger.info("這是一條普通訊息存入myapp3")

注意呼叫logger.remove()之後的所有日誌將不會被記錄,因為沒有處理器了。

from loguru import logger
# 移除所有日誌處理器(包括終端輸出)
logger.remove()
# 沒有輸出
logger.info("這是一條普通訊息存入myapp3")

如果希望移除某些日誌處理器,而不是從所有日誌器中移除,程式碼如下:

from loguru import logger

# 移除預設終端logger,如果終端存在。
# logger.remove(0)
# 新增多個檔案處理器,enqueu設定非同步日誌記錄
handler1 = logger.add("myapp1.log", enqueue=True)
print(handler1) # handler_id是移除的處理器的唯一識別符號
handler2 = logger.add("myapp2.log")

# 記錄一些日誌
logger.info("這些資訊會被記錄到兩個檔案中")

# 移除特定的檔案處理器
logger.remove(handler1)

# 現在只有myapp2.log 會記錄日誌
logger.info("這條資訊只會記錄在myapp2.log 中")

如果想將日誌輸出到日誌臺,程式碼如下:

from loguru import logger
import sys

logger.remove() # 移除預設輸出
# 新增一個日誌處理器,輸出到控制檯,使用自定義格式
logger.add(
    sink=sys.stdout,
    level="DEBUG",
    # green表示顏色
    format="<green>{time:HH:mm}</green> <level>{message}</level>"
)

# 注意終端顯示會同步顯示
logger.debug("這是一條除錯資訊")
logger.info("這是一條普通訊息")

時間自定義

可以使用datatime庫來自定義日誌時間格式。

from datetime import datetime
from loguru import logger

# 自定義時間格式
# time_format = "%Y-%m-%d %H:%M:%S,%f"  # 包括微秒
time_format = "%H:%M:%S,%f"  # 包括微秒但不含年月日

# 定義日誌格式,使用 datetime.now().strftime() 來格式化時間
log_format = "{time:" + time_format + "} - {level} - {message}"
logger.add("myapp.log", format=log_format, level="DEBUG")

# 記錄一條日誌
logger.debug("這是一個帶有微秒的測試日誌")

日誌輪換

from loguru import logger
# 當檔案大小達到100MB時建立新的日誌檔案,舊檔案保留並重新命名,用於防止單個日誌檔案變得過大。
logger.add("file_1.log", rotation="100 MB")
# 每天中午12時建立新的日誌檔案,舊檔案保留並重新命名
logger.add("file_2.log", rotation="12:00")
# 當日志檔案存在超過一週時建立新的日誌檔案,舊檔案保留並重新命名
logger.add("file_3.log", rotation="1 week")
# 設定日誌檔案保留10天
logger.add("file_4.log", retention="10 days")
# 當檔案大小達到100MB時建立新的日誌檔案,舊檔案保留壓縮為zip檔案
logger.add('file_{time}.log', rotation="100 MB", compression='zip')

1.3 進階使用

異常捕獲

@logger.catch裝飾器可以用來裝飾my_function函式,並將這些異常資訊記錄到日誌中。

from loguru import logger

logger.add(sink='myapp.log')

@logger.catch
def my_function(x, y):
    return x / y
        
res = my_function(0,0)

過濾

使用loguru庫進行Python日誌記錄時,可以透過自定義的filter函式來篩選並記錄特定的日誌資訊。此函式接收一個記錄物件作為引數,根據日誌訊息內容(message)、級別(level)或其他日誌屬性,返回布林值以決定是否記錄該條日誌。如果函式返回True,則日誌被記錄;若返回False,則忽略該日誌。

from loguru import logger

# 定義一個過濾器函式
def my_filter(record):
    # 只記錄包含 "第一" 的日誌
    return "第一" in record["message"]

# 使用過濾器
logger.add("myapp.log", filter=my_filter)

# 記錄一些日誌
logger.info("第一個記錄")
logger.info("第二個記錄")

此外可以結合bind方法進行過濾,bind方法用於向日志記錄器新增額外的上下文資訊。這些資訊將被包含在每條日誌訊息中,但不會改變日誌訊息本身。如下所示:

from loguru import logger

def filter_user(record):
    return record["extra"].get("user") =="A"

logger.add("myapp.log", filter=filter_user)

# 繫結user
logger.bind(user="A").info("來自A")
logger.bind(user="B").info("來自B")

2 參考

  • loguru
  • loguru-doc
  • Python日誌記錄庫logging總結
  • Python日誌庫Loguru教程

相關文章