首頁 > 軟體

Python3 Loguru輸出紀錄檔工具的使用

2022-05-15 19:00:15

一、前言

Python logging 模組定義了為應用程式和庫實現靈活的事件紀錄檔記錄的函數和類。

程式開發過程中,很多程式都有記錄紀錄檔的需求,並且紀錄檔包含的資訊有正常的程式存取紀錄檔還可能有錯誤、警告等資訊輸出,Python 的 logging 模組提供了標準的紀錄檔介面,可以通過它儲存各種格式的紀錄檔,紀錄檔記錄提供了一組便利功能,用於簡單的紀錄檔記錄用法。

使用 Python Logging 模組的主要好處是所有 Python 模組都可以參與紀錄檔記錄Logging 模組提供了大量具有靈活性的功能。

為什麼要使用loguru?

簡單且方便的幫助我們輸出需要的紀錄檔資訊:

使用 Python 來寫程式或者指令碼的話,常常遇到的問題就是需要對紀錄檔進行刪除。一方面可以幫助我們在程式出問題的時候排除問題,二來可以幫助我們記錄需要關注的資訊。
但是,使用自帶自帶的 logging 模組的話,則需要我們進行不同的初始化等相關工作。對應不熟悉該模組的同學來說,還是有些費勁的,比如需要設定 Handler/Formatter 等。 隨著業務的複雜度提升, 對紀錄檔收集有著更高的要求, 例如: 紀錄檔分類, 檔案儲存, 非同步寫入, 自定義型別等等

loguru 是一個 Python 簡易且強大的第三方紀錄檔記錄庫,該庫旨在通過新增一系列有用的功能來解決標準記錄器的注意事項,從而減少 Python 紀錄檔記錄的痛苦。

二、優雅的使用loguru

1. 安裝loguru

pip install loguru 

2.功能特性介紹

有很多優點,以下列舉了其中比較重要的幾點:

  • 開箱即用,無需準備
  • 無需初始化,匯入函數即可使用
  • 更容易的檔案紀錄檔記錄與轉存/保留/壓縮方式
  • 更優雅的字串格式化輸出
  • 可以線上程或主執行緒中捕獲異常
  • 可以設定不同級別的紀錄檔記錄樣式
  • 支援非同步,且執行緒和多程序安全
  • 支援惰性計算
  • 適用於指令碼和庫
  • 完全相容標準紀錄檔記錄
  • 更好的日期時間處理

3. 開箱即用,無需準備

from loguru import logger  
logger.debug("That's it, beautiful and simple logging!")  

無需初始化,匯入函數即可使用, 那麼你肯定要問, 如何解決一下問題?

  • 如何新增處理程式(handler)呢?
  • 如何設定紀錄檔格式(logs formatting)呢?
  • 如何過濾訊息(filter messages)呢?
  • 如何如何設定級別(log level)呢?
# add  
logger.add(sys.stderr,   
    format="{time} {level} {message}",  
    filter="my_module",  
    level="INFO") 

是不是很easy~

4. 更容易的檔案紀錄檔記錄與轉存/保留/壓縮方式

# 紀錄檔檔案記錄  
logger.add("file_{time}.log")  
# 紀錄檔檔案轉存  
logger.add("file_{time}.log", rotation="500 MB")  
logger.add("file_{time}.log", rotation="12:00")  
logger.add("file_{time}.log", rotation="1 week")  
# 多次時間之後清理  
logger.add("file_X.log", retention="10 days")  
# 使用zip檔案格式儲存  
logger.add("file_Y.log", compression="zip") 

5. 更優雅的字串格式化輸出

logger.info(  
    "If you're using Python {}, prefer {feature} of course!",  
    3.10, feature="f-strings") 

6. 在子執行緒或主執行緒中捕獲異常

@logger.catch  
def my_function(x, y, z):  
    # An error? It's caught anyway!  
    return 1 / (x + y + z)  
my_function(0, 0, 0) 

7. 可以設定不同級別的紀錄檔記錄樣式

Loguru 會自動為不同的紀錄檔級別,新增不同的顏色進行區分, 也支援自定義顏色哦~

logger.add(sys.stdout,  
    colorize=True,  
    format="<green>{time}</green> <level>{message}</level>")  
logger.add('logs/z_{time}.log',  
           level='DEBUG',  
           format='{time:YYYY-MM-DD :mm:ss} - {level} - {file} - {line} - {message}',  
           rotation="10 MB") 

8.支援非同步且執行緒和多程序安全

  • 預設情況下,新增到 logger 中的紀錄檔資訊都是執行緒安全的。但這並不是多程序安全的,我們可以通過新增 enqueue 引數來確保紀錄檔完整性。
  • 如果我們想要在非同步任務中使用紀錄檔記錄的話,也是可以使用同樣的引數來保證的。並且通過 complete() 來等待執行完成。
# 非同步寫入  
logger.add("some_file.log", enqueue=True)  

你沒有看錯, 只需要enqueue=True即可非同步執行

9. 異常的完整性描述

用於記錄程式碼中發生的異常的 bug 跟蹤,Loguru 通過允許顯示整個堆疊跟蹤(包括變數值)來幫助您識別問題

logger.add("out.log", backtrace=True, diagnose=True)  
def func(a, b):  
    return a / b  
def nested(c):  
    try:  
        func(5, c)  
    except ZeroDivisionError:  
        logger.exception("What?!")  
nested(0) 

10. 結構化紀錄檔記錄

  • 對紀錄檔進行序列化以便更容易地解析或傳遞資料結構,使用序列化引數,在將每個紀錄檔訊息傳送到設定的接收器之前,將其轉換為 JSON 字串。
  • 同時,使用 bind() 方法,可以通過修改額外的 record 屬性來將紀錄檔記錄器訊息置於上下文中。還可以通過組合 bind() 和 filter 對紀錄檔進行更細粒度的控制。
  • 最後 patch() 方法允許將動態值附加到每個新訊息的記錄 dict 上。
# 序列化為json格式  
logger.add(custom_sink_function, serialize=True)  
# bind方法的用處  
logger.add("file.log", format="{extra[ip]} {extra[user]} {message}")  
context_logger = logger.bind(ip="192.168.2.174", user="someone")  
context_logger.info("Contextualize your logger easily")  
context_logger.bind(user="someone_else").info("Inline binding of extra attribute")  
context_logger.info("Use kwargs to add context during formatting: {user}", user="anybody")  
# 粒度控制  
logger.add("special.log", filter=lambda record: "special" in record["extra"])  
logger.debug("This message is not logged to the file")  
logger.bind(special=True).info("This message, though, is logged to the file!")  
# patch()方法的用處  
logger.add(sys.stderr, format="{extra[utc]} {message}")  
loggerlogger = logger.patch(lambda record: record["extra"].update(utc=datetime.utcnow()))

11. 惰性計算

有時希望在生產環境中記錄詳細資訊而不會影響效能,可以使用 opt() 方法來實現這一點。

logger.opt(lazy=True).debug("If sink level <= DEBUG: {x}", x=lambda: expensive_function(2**64))  
# By the way, "opt()" serves many usages  
logger.opt(exception=True).info("Error stacktrace added to the log message (tuple accepted too)")  
logger.opt(colors=True).info("Per message <blue>colors</blue>")  
logger.opt(record=True).info("Display values from the record (eg. {record[thread]})")  
logger.opt(raw=True).info("Bypass sink formattingn")  
logger.opt(depth=1).info("Use parent stack context (useful within wrapped functions)")  
logger.opt(capture=False).info("Keyword arguments not added to {dest} dict", dest="extra") 

12. 可客製化的級別

new_level = logger.level("SNAKY", no=38, color="<yellow>", icon="

IT145.com E-mail:sddin#qq.com