fastapi loguru


使用loguru記錄日志

安裝

pip install loguru

基本使用

那么這個庫怎么來用呢?我們先用一個實例感受下:

In [1]: from loguru import logger ...: ...: logger.debug('this is a debug message') 

看到了吧,不需要配置什么東西,直接引入一個 logger,然后調用其 debug方法即可。

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

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

2019-11-06 22:45:31.653 | DEBUG | __main__:<module>:3 - this is a debug message 

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

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

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

In [2]: from loguru import logger ...: ...: logger.add('runtime.log') ...: logger.debug('this is a debug') 

很簡單吧,我們也不需要再聲明一個 FileHandler 了,就一行 add 語句搞定,運行之后會發現目錄下 runtime.log 里面同樣出現了剛剛控制台輸出的 DEBUG 信息。

cat runtime.log
2019-11-06 22:46:59.690 | DEBUG    | __main__:<module>:4 - this is a debug

上面就是一些基本的使用,但這還遠遠不夠,下面我們來詳細了解下它的一些功能模塊。·

詳細使用

既然是日志,那么最常見的就是輸出到文件了。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 ): r"""Add a handler sending log messages to a sink adequately configured. 

看看它的源代碼,它支持這么多的參數,如 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 字符串路徑,他就給我們創建了一個日志文件,就是這個原理。

基本參數

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

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

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

刪除 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 方法,再次輸出一條日志,看看結果是怎樣的。

控制台輸出如下:

2019-11-06 23:03:24.368 | DEBUG | __main__:<module>:4 - this is a debug message 2019-11-06 23:03:24.369 | DEBUG | __main__:<module>:6 - this is another debug message 

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

cat runtime.log
2019-11-06 23:03:24.368 | DEBUG    | __main__:<module>:4 - this is a debug message

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

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

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 文件了。

- an |int| which corresponds to the maximum file size in bytes before that the current logged file is closed and a new one started over. - a |timedelta| which indicates the frequency of each new rotation. - a |time| which specifies the hour when the daily rotation should occur. - a |str| for human-friendly parametrization of one of the previously enumerated types. Examples: ``"100 MB"``, ``"0.5 GB"``, ``"1 month 2 weeks"``, ``"4 days"``, ``"10h"``, ``"monthly"``, ``"18:00"``, ``"sunday"``, ``"w0"``, ``"monday at 12:00"``, ... - a |function|_ which will be called before logging. It should accept two arguments: the logged message and the file object, and it should return ``True`` if the rotation should happen now, ``False`` otherwise. 

retention 配置

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

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

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

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

我們看下源碼看下這個參數可以設置為哪些值:

- an |int| which indicates the number of log files to keep, while older files are removed. - a |timedelta| which specifies the maximum age of files to keep. - a |str| for human-friendly parametrization of the maximum age of files to keep. Examples: ``"1 week, 3 days"``, ``"2 months"``, ... - a |function|_ which will be called before the retention process. It should accept the list of log files as argument and process to whatever it wants (moving files, removing them, etc.). 

compression 配置

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

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

這樣可以更加節省存儲空間。

我們看下源碼看下這個參數可以設置為哪些值:

- a |str| which corresponds to the compressed or archived file extension. This can be one of: ``"gz"``, ``"bz2"``, ``"xz"``, ``"lzma"``, ``"tar"``, ``"tar.gz"``, ``"tar.bz2"``, ``"tar.xz"``, ``"zip"``. - a |function|_ which will be called before file termination. It should accept the path of the log file as argument and process to whatever it wants (custom compression, network sending, removing it, etc.). 

enqueue配置

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

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

看下源碼的解釋:

enqueue : |bool|, optional Whether the messages to be logged should first pass through a multiprocess-safe queue before reaching the sink. This is useful while logging to a file through multiple processes. 

字符串格式化

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

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

這樣在添加參數就非常方便了。

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 

因此,用 loguru 可以非常方便地實現日志追蹤,debug 效率可能要高上十倍了?

Want to intercept standard logging messages toward your Loguru sinks?

class InterceptHandler(logging.Handler): def emit(self, record): # Retrieve context where the logging call occurred, this happens to be in the 6th frame upward logger_opt = logger.opt(depth=6, exception=record.exc_info) logger_opt.log(record.levelno, record.getMessage()) logging.basicConfig(handlers=[InterceptHandler()], level=0)


免責聲明!

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



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