天天看點

loguru包的使用

loguru包的使用

= 'INFO'

    if not os.path.exists(logs_path):
        os.makedirs(logs_path)
    if not os.path.exists(data_path):
        os.makedirs(data_path)
    if not os.path.exists(conf_path):
        os.makedirs(conf_path)

    logger.remove(handler_id=None)

    logger.add(
        sys.stdout, 
        colorize=True, 
        enqueue=True,
        level=log_level
    )

    logger.add(
        os.path.join(logs_path, 'hot_news.trace.log'),
        filter=lambda x: 'TRACE' in str(x['level']).upper(),
        enqueue=True,
        rotation="00:00",
        level=log_level
    )

    logger.add(
        os.path.join(logs_path, 'hot_news.debug.log'),
        filter=lambda x: 'DEBUG' in str(x['level']).upper(),
        enqueue=True,
        rotation="00:00",
        level=log_level
    )

    logger.add(
        os.path.join(logs_path, 'hot_news.info.log'),
        filter=lambda x: 'INFO' in str(x['level']).upper(),
        enqueue=True,
        rotation="00:00",
        level=log_level
    )

    logger.add(
        os.path.join(logs_path, 'hot_news.error.log'),
        filter=lambda x: 'ERROR' in str(x['level']).upper(),
        enqueue=True,
        rotation="00:00",
        level=log_level
    )      

詳細說明

既然是日志,那麼最常見的就是輸出到檔案了。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
    ):
    pass      

看看它的源代碼,它支援這麼多的參數,如 level、format、filter、color 等等,另外我們還注意到它有個非常重要的參數 sink,我們看看官方文檔:​​https://loguru.readthedocs.io/en/stable/api/logger.html#sink​​

可以通過sink,我們可以傳入多種不同的資料結構,彙總如下:

  • sink 可以傳入一個 file 對象,例如​

    ​sys.stderr​

    ​​ 或者​

    ​open('file.log', 'w')​

    ​ 都可以。
  • sink 可以直接傳入一個​

    ​str​

    ​​ 字元串或者​

    ​pathlib.Path​

    ​ 對象,其實就是代表檔案路徑的,如果識别到是這種類型,它會自動建立對應路徑的日志檔案并将日志輸出進去。
  • sink 可以是一個方法,可以自行定義輸出實作。
  • sink 可以是一個 logging 子產品的 Handler,比如 FileHandler、StreamHandler 等等,或者上文中我們提到的 CMRESHandler 照樣也是可以的,這樣就可以實作自定義 Handler 的配置。
  • sink 還可以是一個自定義的類,具體的實作規範可以參見官方文檔。

是以說,剛才我們所示範的輸出到檔案,僅僅給它傳了一個 str 字元串路徑,他就給我們建立了一個日志檔案,就是這個原理。

上述代碼中我們将INFO級别的日志打到了sys.stdout中,可以在輸出流中看到INFO的日志

基本參數

下面我們再了解下它的其他參數,例如 format、filter、level 等等。 其實它們的概念和格式和 logging 子產品都是基本一樣的了,例如這裡使用 format、filter、level 來規定輸出的格式:

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-10-13 23:18:26.469 | DEBUG    | __main__:<module>:4 - this is a debug message
2019-10-13 23:18:26.469 | DEBUG    | __main__:<module>:6 - this is      

日志檔案 runtime.log 内容如下:

2019-10-13 23:18:26.469 | DEBUG    | __main__:<module>:4 - this is      

可以發現,在調用 remove 方法之後,确實将曆史 log 删除了。但實際上這并不是删除,隻不過是将 sink 對象移除之後,在這之前的内容不會再輸出到日志中。 這樣我們就可以實作日志的重新整理重新寫入操作。

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 檔案了。

retention 配置

很多情況下,一些非常久遠的 log 對我們來說并沒有什麼用處了,它白白占據了一些存儲空間,不清除掉就會非常浪費。retention 這個參數可以配置日志的最長保留時間。 比如我們想要設定日志檔案最長保留 10 天,可以這麼來配置:

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

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

compression 配置

loguru 還可以配置檔案的壓縮格式,比如使用 zip 檔案格式儲存,示例如下:

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

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

字元串格式化

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)      
\> 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: