『Python』優雅的記錄日志——loguru


1. 安裝

pip install loguru

2. 初識

from loguru import logger

logger.debug("This is a debug...")

loguru 里面有且僅有一個主要對象,那就是 loggerloguru 里面有且僅有一個 logger,而且它已經被提前配置了一些基礎信息,比如比較友好的格式化、文本顏色信息等等。

上面的代碼運行結果如下:

2020-05-03 09:22:35.746 | DEBUG    | __main__:<module>:3 - This is a debug...

可以看到其默認的輸出格式是上面的內容,有時間、級別、模塊名、行號以及日志信息,不需要手動創建 logger,直接使用即可,另外其輸出還是彩色的,看起來會更加友好。

以上的日志信息是直接輸出到控制台的,並沒有輸出到其他的地方,如果想要輸出到其他的位置,比如存為文件,我們只需要使用一行代碼聲明即可。

例如將結果同時輸出到一個 runtime.log 文件里面,可以這么寫:

from loguru import logger

logger.add("runtime.log")
logger.debug("This is a debug...")
logger.warning("This is a debug...")

一行 add 語句搞定,運行之后會發現目錄下 runtime.log 里面同樣出現了剛剛控制台輸出的 DEBUG 信息。

2020-05-03 09:26:09.212 | DEBUG    | __main__:<module>:4 - This is a debug...
2020-05-03 09:26:09.212 | WARNING  | __main__:<module>:5 - This is a debug...

3. 使用

既然是日志,那么最常見的就是輸出到文件了。loguru 對輸出到文件的配置有非常強大的支持,比如支持輸出到多個文件,分級別分別輸出,過大創建新文件,過久自動刪除等等。

下面我們分別看看這些怎樣來實現,這里基本上就是 add 方法的使用介紹。因為這個 add 方法就相當於給 logger 添加了一個 Handler,它給我們暴露了許多參數來實現 Handler 的配置,下面我們來詳細介紹下。

首先看看它的方法定義吧:

def add(
    self,
    sink,
    *,
    level=_defaults.LOGURU_LEVEL,
    format=_defaults.LOGURU_FORMAT,
    filter=_defaults.LOGURU_FILTER,
    colorize=_defaults.LOGURU_COLORIZE,
    serialize=_defaults.LOGURU_SERIALIZE,
    backtrace=_defaults.LOGURU_BACKTRACE,
    diagnose=_defaults.LOGURU_DIAGNOSE,
    enqueue=_defaults.LOGURU_ENQUEUE,
    catch=_defaults.LOGURU_CATCH,
    **kwargs
)

看看它的源代碼,它支持這么多的參數,如 levelformatfiltercolor 等等,另外我們還注意到它有個非常重要的參數 sink,我們看看官方文檔:sink,可以了解到通過 sink 我們可以傳入多種不同的數據結構,匯總如下:

  • sink 可以傳入一個 file 對象,例如 sys.stderr 或者 open('file.log', 'w') 都可以。

  • sink 可以直接傳入一個 str 字符串或者 pathlib.Path 對象,其實就是代表文件路徑的,如果識別到是這種類型,它會自動創建對應路徑的日志文件並將日志輸出進去。

  • sink 可以是一個方法,可以自行定義輸出實現。

  • sink 可以是一個 logging 模塊的 Handler,比如 FileHandlerStreamHandler 等等,或者上文中我們提到的 CMRESHandler 照樣也是可以的,這樣就可以實現自定義 Handler 的配置。

  • sink 還可以是一個自定義的類,具體的實現規范可以參見官方文檔。

所以說,剛才我們所演示的輸出到文件,僅僅給它傳了一個 str 字符串路徑,他就給我們創建了一個日志文件,就是這個原理。

3.1 基本參數

下面我們再了解下它的其他參數,例如 formatfilterlevel 等等。

其實它們的概念和格式和 logging 模塊都是基本一樣的了,例如這里使用formatfilterlevel來規定輸出的格式:

logger.add('runtime.log', format="{time} {level} {message}", filter="my_module", level="INFO")

3.2 刪除sink

另外添加 sink 之后我們也可以對其進行刪除,相當於重新刷新並寫入新的內容。

刪除的時候根據剛剛 add 方法返回的 id 進行刪除即可,看下面的例子:

from loguru import logger
 
trace = logger.add('runtime.log')
logger.debug('this is a debug message')
logger.remove(trace)
logger.debug('this is another debug message')

看這里,我們首先 add 了一個 sink,然后獲取它的返回值,賦值為 trace。隨后輸出了一條日志,然后將 trace 變量傳給remove 方法,再次輸出一條日志,看看結果是怎樣的。

控制台輸出如下:

2020-05-03 09:55:11.005 | DEBUG    | __main__:<module>:4 - this is a debug message
2020-05-03 09:55:11.005 | DEBUG    | __main__:<module>:6 - this is another debug message

日志文件 runtime.log 內容如下:

2020-05-03 09:55:11.005 | DEBUG    | __main__:<module>:4 - this is a debug message

可以發現,在調用 remove 方法之后,確實將歷史 log 刪除了。

這樣我們就可以實現日志的刷新重新寫入操作。

3.3 rotation配置

用了 loguru 我們還可以非常方便地使用rotation 配置,比如我們想一天輸出一個日志文件,或者文件太大了自動分隔日志文件,我們可以直接使用 add 方法的 rotation 參數進行配置。

我們看看下面的例子:

logger.add('runtime_{time}.log', rotation="500 MB")

通過這樣的配置我們就可以實現每 500MB 存儲一個文件,每個 log 文件過大就會新創建一個 log 文件。我們在配置 log 名字時加上了一個 time 占位符,這樣在生成時可以自動將時間替換進去,生成一個文件名包含時間的 log 文件。

另外我們也可以使用 rotation 參數實現定時創建 log 文件,例如:

logger.add('runtime_{time}.log', rotation='00:00')

這樣就可以實現每天 0 點新創建一個 log 文件輸出了。

另外我們也可以配置 log 文件的循環時間,比如每隔一周創建一個 log 文件,寫法如下:

logger.add('runtime_{time}.log', rotation='1 week')

這樣我們就可以實現一周創建一個 log 文件了。

3.4 retention 配置

很多情況下,一些非常久遠的 log 對我們來說並沒有什么用處了,它白白占據了一些存儲空間,不清除掉就會非常浪費。retention 這個參數可以配置日志的最長保留時間。

比如我們想要設置日志文件最長保留 10 天,可以這么來配置:

logger.add('runtime.log', retention='10 days')

Examples: "1 week, 3 days", "2 months"

這樣 log 文件里面就會保留最新 10 天的 log,媽媽再也不用擔心 log 沉積的問題啦。

3.5 compression配置

loguru 還可以配置文件的壓縮格式,比如使用 zip 文件格式保存,示例如下:

logger.add('runtime.log', compression='zip')

可選格式為"gz", "bz2", "xz", "lzma", "tar", "tar.gz", "tar.bz2",
"tar.xz", "zip"

3.6 enqueue配置

loguru可以配置在多進程同時往日志文件寫日志的時候使用隊列達到異步功效。

logger.add("somefile.log", enqueue=True)  # 異步寫入

要記錄的消息是否應該在到達接收器之前首先通過一個多進程安全的隊列。這在通過多個進程記錄文件時非常有用。

3.7 字符串格式化

loguru 在輸出 log 的時候還提供了非常友好的字符串格式化功能,像這樣:

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

輸出:

2020-05-03 10:24:34.200 | INFO     | __main__:<module>:3 - If you are using Python 3.6, prefer f-strings of course!

3.8 Traceback 記錄

在很多情況下,如果遇到運行錯誤,而我們在打印輸出 log 的時候萬一不小心沒有配置好 Traceback 的輸出,很有可能我們就沒法追蹤錯誤所在了。

但用了 loguru 之后,我們用它提供的裝飾器就可以直接進行 Traceback 的記錄,類似這樣的配置即可:

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

我們做個測試,我們在調用時三個參數都傳入 0,直接引發除以 0 的錯誤,看看會出現什么情況

my_function(0, 0, 0)

運行完畢之后,可以發現 log 里面就出現了 Traceback 信息,而且給我們輸出了當時的變量值,真的是不能再贊了!結果如下:

> File "run.py", line 15, in <module>
    my_function(0, 0, 0)
    └ <function my_function at 0x1171dd510>
 
  File "/private/var/py/logurutest/demo5.py", line 13, in my_function
    return 1 / (x + y + z)
                │   │   └ 0
                │   └ 0
                └ 0
 
ZeroDivisionError: division by zero


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM