欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python3?Loguru輸出日志工具的使用

 更新時(shí)間:2022年05月15日 13:49:45   作者:韓俊強(qiáng)  
使用 Python 來(lái)寫(xiě)程序或者腳本的話(huà),常常遇到的問(wèn)題就是需要對(duì)日志進(jìn)行刪除。一方面可以幫助我們?cè)诔绦虺鰡?wèn)題的時(shí)候排除問(wèn)題,二來(lái)可以幫助我們記錄需要關(guān)注的信息,這篇文章主要介紹了Python3?Loguru?相見(jiàn)恨晚的輸出日志工具,需要的朋友可以參考下

一、前言

Python logging 模塊定義了為應(yīng)用程序和庫(kù)實(shí)現(xiàn)靈活的事件日志記錄的函數(shù)和類(lèi)。

程序開(kāi)發(fā)過(guò)程中,很多程序都有記錄日志的需求,并且日志包含的信息有正常的程序訪(fǎng)問(wèn)日志還可能有錯(cuò)誤、警告等信息輸出,Python 的 logging 模塊提供了標(biāo)準(zhǔn)的日志接口,可以通過(guò)它存儲(chǔ)各種格式的日志,日志記錄提供了一組便利功能,用于簡(jiǎn)單的日志記錄用法。

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

為什么要使用loguru?

簡(jiǎn)單且方便的幫助我們輸出需要的日志信息:

使用 Python 來(lái)寫(xiě)程序或者腳本的話(huà),常常遇到的問(wèn)題就是需要對(duì)日志進(jìn)行刪除。一方面可以幫助我們?cè)诔绦虺鰡?wèn)題的時(shí)候排除問(wèn)題,二來(lái)可以幫助我們記錄需要關(guān)注的信息。
但是,使用自帶自帶的 logging 模塊的話(huà),則需要我們進(jìn)行不同的初始化等相關(guān)工作。對(duì)應(yīng)不熟悉該模塊的同學(xué)來(lái)說(shuō),還是有些費(fèi)勁的,比如需要配置 Handler/Formatter 等。 隨著業(yè)務(wù)的復(fù)雜度提升, 對(duì)日志收集有著更高的要求, 例如: 日志分類(lèi), 文件存儲(chǔ), 異步寫(xiě)入, 自定義類(lèi)型等等

loguru 是一個(gè) Python 簡(jiǎn)易且強(qiáng)大的第三方日志記錄庫(kù),該庫(kù)旨在通過(guò)添加一系列有用的功能來(lái)解決標(biāo)準(zhǔn)記錄器的注意事項(xiàng),從而減少 Python 日志記錄的痛苦。

二、優(yōu)雅的使用loguru

1. 安裝loguru

pip install loguru 

2.功能特性介紹

有很多優(yōu)點(diǎn),以下列舉了其中比較重要的幾點(diǎn):

  • 開(kāi)箱即用,無(wú)需準(zhǔn)備
  • 無(wú)需初始化,導(dǎo)入函數(shù)即可使用
  • 更容易的文件日志記錄與轉(zhuǎn)存/保留/壓縮方式
  • 更優(yōu)雅的字符串格式化輸出
  • 可以在線(xiàn)程或主線(xiàn)程中捕獲異常
  • 可以設(shè)置不同級(jí)別的日志記錄樣式
  • 支持異步,且線(xiàn)程和多進(jìn)程安全
  • 支持惰性計(jì)算
  • 適用于腳本和庫(kù)
  • 完全兼容標(biāo)準(zhǔn)日志記錄
  • 更好的日期時(shí)間處理

3. 開(kāi)箱即用,無(wú)需準(zhǔn)備

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

無(wú)需初始化,導(dǎo)入函數(shù)即可使用, 那么你肯定要問(wèn), 如何解決一下問(wèn)題?

  • 如何添加處理程序(handler)呢?
  • 如何設(shè)置日志格式(logs formatting)呢?
  • 如何過(guò)濾消息(filter messages)呢?
  • 如何如何設(shè)置級(jí)別(log level)呢?
# add  
logger.add(sys.stderr, \  
    format="{time} {level} {message}",\  
    filter="my_module",\  
    level="INFO") 

是不是很easy~

4. 更容易的文件日志記錄與轉(zhuǎn)存/保留/壓縮方式

# 日志文件記錄  
logger.add("file_{time}.log")  
# 日志文件轉(zhuǎn)存  
logger.add("file_{time}.log", rotation="500 MB")  
logger.add("file_{time}.log", rotation="12:00")  
logger.add("file_{time}.log", rotation="1 week")  
# 多次時(shí)間之后清理  
logger.add("file_X.log", retention="10 days")  
# 使用zip文件格式保存  
logger.add("file_Y.log", compression="zip") 

5. 更優(yōu)雅的字符串格式化輸出

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

6. 在子線(xiàn)程或主線(xiàn)程中捕獲異常

@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. 可以設(shè)置不同級(jí)別的日志記錄樣式

Loguru 會(huì)自動(dòng)為不同的日志級(jí)別,添加不同的顏色進(jìn)行區(qū)分, 也支持自定義顏色哦~

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.支持異步且線(xiàn)程和多進(jìn)程安全

  • 默認(rèn)情況下,添加到 logger 中的日志信息都是線(xiàn)程安全的。但這并不是多進(jìn)程安全的,我們可以通過(guò)添加 enqueue 參數(shù)來(lái)確保日志完整性。
  • 如果我們想要在異步任務(wù)中使用日志記錄的話(huà),也是可以使用同樣的參數(shù)來(lái)保證的。并且通過(guò) complete() 來(lái)等待執(zhí)行完成。
# 異步寫(xiě)入  
logger.add("some_file.log", enqueue=True)  

你沒(méi)有看錯(cuò), 只需要enqueue=True即可異步執(zhí)行

9. 異常的完整性描述

用于記錄代碼中發(fā)生的異常的 bug 跟蹤,Loguru 通過(guò)允許顯示整個(gè)堆棧跟蹤(包括變量值)來(lái)幫助您識(shí)別問(wèn)題

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. 結(jié)構(gòu)化日志記錄

  • 對(duì)日志進(jìn)行序列化以便更容易地解析或傳遞數(shù)據(jù)結(jié)構(gòu),使用序列化參數(shù),在將每個(gè)日志消息發(fā)送到配置的接收器之前,將其轉(zhuǎn)換為 JSON 字符串。
  • 同時(shí),使用 bind() 方法,可以通過(guò)修改額外的 record 屬性來(lái)將日志記錄器消息置于上下文中。還可以通過(guò)組合 bind() 和 filter 對(duì)日志進(jìn)行更細(xì)粒度的控制。
  • 最后 patch() 方法允許將動(dòng)態(tài)值附加到每個(gè)新消息的記錄 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. 惰性計(jì)算

有時(shí)希望在生產(chǎn)環(huán)境中記錄詳細(xì)信息而不會(huì)影響性能,可以使用 opt() 方法來(lái)實(shí)現(xiàn)這一點(diǎn)。

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 formatting\n")  
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. 可定制的級(jí)別

new_level = logger.level("SNAKY", no=38, color="<yellow>", icon="??")  
logger.log("SNAKY", "Here we go!") 

13. 適用于腳本和庫(kù)

# For scripts  
config = {  
    "handlers": [  
        {"sink": sys.stdout, "format": "{time} - {message}"},  
        {"sink": "file.log", "serialize": True},  
    ],  
    "extra": {"user": "someone"}  
}  
logger.configure(**config)  
# For libraries  
logger.disable("my_library")  
logger.info("No matter added sinks, this message is not displayed")  
logger.enable("my_library")  
logger.info("This message however is propagated to the sinks") 

14. 完全兼容標(biāo)準(zhǔn)日志記錄

  • 希望使用 Loguru 作為內(nèi)置的日志處理程序?
  • 需要將 Loguru 消息到標(biāo)準(zhǔn)日志?
  • 想要攔截標(biāo)準(zhǔn)的日志消息到 Loguru 中匯總?
handler = logging.handlers.SysLogHandler(address=('localhost', 514)) 
logger.add(handler)  
class PropagateHandler(logging.Handler):  
    def emit(self, record):  
        logging.getLogger(record.name).handle(record)  
logger.add(PropagateHandler(), format="{message}")  
class InterceptHandler(logging.Handler):  
    def emit(self, record):  
        # Get corresponding Loguru level if it exists  
        try:  
            level = logger.level(record.levelname).name  
        except ValueError:  
            level = record.levelno  
        # Find caller from where originated the logged message  
        frame, depth = logging.currentframe(), 2  
        while frame.f_code.co_filename == logging.__file__:  
            frameframe = frame.f_back  
            depth += 1  
        logger.opt(depthdepth=depth, exception=record.exc_info).log(level, record.getMessage())  
logging.basicConfig(handlers=[InterceptHandler()], level=0) 

15. 非常方便的解析器

從生成的日志中提取特定的信息通常很有用,這就是為什么 Loguru 提供了一個(gè) parse() 方法來(lái)幫助處理日志和正則表達(dá)式。

pattern = r"(?P<time>.*) - (?P<level>[0-9]+) - (?P<message>.*)"  # Regex with named groups  
caster_dict = dict(time=dateutil.parser.parse, level=int)        # Transform matching groups  
for groups in logger.parse("file.log", pattern, cast=caster_dict):  
    print("Parsed:", groups) 
    # {"level": 30, "message": "Log example", "time": datetime(2018, 12, 09, 11, 23, 55)}

16. 通知機(jī)制 (郵件告警)

import notifiers  
params = {  
    "username": "you@gmail.com",  
    "password": "abc123",  
    "to": "dest@gmail.com"  
}  
# Send a single notification  
notifier = notifiers.get_notifier("gmail")  
notifier.notify(message="The application is running!", **params)  
# Be alerted on each error message  
from notifiers.logging import NotificationHandler  
handler = NotificationHandler("gmail", defaults=params)  
logger.add(handler, level="ERROR") 

17. Flask 框架集成

  • 現(xiàn)在最關(guān)鍵的一個(gè)問(wèn)題是如何兼容別的 logger,比如說(shuō) tornado 或者 django 有一些默認(rèn)的 logger。
  • 經(jīng)過(guò)研究,最好的解決方案是參考官方文檔的,完全整合 logging 的工作方式。比如下面將所有的 logging都用 loguru 的 logger 再發(fā)送一遍消息。
import logging  
import sys  
from pathlib import Path  
from flask import Flask  
from loguru import logger  
app = Flask(__name__)  
class InterceptHandler(logging.Handler):  
    def emit(self, record):  
        loggerlogger_opt = logger.opt(depth=6, exception=record.exc_info)  
        logger_opt.log(record.levelname, record.getMessage())  
def configure_logging(flask_app: Flask):  
    """配置日志"""  
    path = Path(flask_app.config['LOG_PATH'])  
    if not path.exists():  
        path.mkdir(parents=True)  
    log_name = Path(path, 'sips.log')  
    logging.basicConfig(handlers=[InterceptHandler(level='INFO')], level='INFO')  
    # 配置日志到標(biāo)準(zhǔn)輸出流  
    logger.configure(handlers=[{"sink": sys.stderr, "level": 'INFO'}])  
    # 配置日志到輸出到文件  
    logger.add(log_name, rotation="500 MB", encoding='utf-8', colorize=False, level='INFO') 

18. 要點(diǎn)解析

介紹,主要函數(shù)的使用方法和細(xì)節(jié) - add()的創(chuàng)建和刪除

  • add() 非常重要的參數(shù) sink 參數(shù)
  • 具體的實(shí)現(xiàn)規(guī)范可以參見(jiàn)官方文檔
  • 可以實(shí)現(xiàn)自定義 Handler 的配置,比如 FileHandler、StreamHandler 等等
  • 可以自行定義輸出實(shí)現(xiàn)
  • 代表文件路徑,會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)路徑的日志文件并將日志輸出進(jìn)去
  • 例如 sys.stderr 或者 open(‘file.log’, ‘w’) 都可以
  • 可以傳入一個(gè) file 對(duì)象
  • 可以直接傳入一個(gè) str 字符串或者 pathlib.Path 對(duì)象
  • 可以是一個(gè)方法
  • 可以是一個(gè) logging 模塊的 Handler
  • 可以是一個(gè)自定義的類(lèi)
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  
): 

另外添加 sink 之后我們也可以對(duì)其進(jìn)行刪除,相當(dāng)于重新刷新并寫(xiě)入新的內(nèi)容。刪除的時(shí)候根據(jù)剛剛 add 方法返回的 id 進(jìn)行刪除即可。可以發(fā)現(xiàn),在調(diào)用 remove 方法之后,確實(shí)將歷史 log 刪除了。但實(shí)際上這并不是刪除,只不過(guò)是將 sink 對(duì)象移除之后,在這之前的內(nèi)容不會(huì)再輸出到日志中,這樣我們就可以實(shí)現(xiàn)日志的刷新重新寫(xiě)入操作

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')  

三、總結(jié)

我們?cè)陂_(kāi)發(fā)流程中, 通過(guò)日志快速定位問(wèn)題, 高效率解決問(wèn)題, 我認(rèn)為 loguru 能幫你解決不少麻煩, 趕快試試吧~

當(dāng)然, 使用各種也有不少麻煩, 例如:

1. 常見(jiàn)錯(cuò)誤1:

--- Logging error in Loguru Handler #3 ---
Record was: None
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/loguru/_handler.py", line 272, in _queued_writer
    message = queue.get()
  File "/usr/local/lib/python3.9/multiprocessing/queues.py", line 366, in get
    res = self._reader.recv_bytes()
  File "/usr/local/lib/python3.9/multiprocessing/connection.py", line 221, in recv_bytes
    buf = self._recv_bytes(maxlength)
  File "/usr/local/lib/python3.9/multiprocessing/connection.py", line 419, in _recv_bytes
    buf = self._recv(4)
  File "/usr/local/lib/python3.9/multiprocessing/connection.py", line 384, in _recv
    chunk = read(handle, remaining)
OSError: [Errno 9] Bad file descriptor
--- End of logging error ---

解決辦法:
嘗試將logs文件夾忽略git提交, 避免和服務(wù)器文件沖突即可;
當(dāng)然也不止這個(gè)原因引起這個(gè)問(wèn)題, 也可能是三方庫(kù)(ciscoconfparse)沖突所致.解決辦法: https://github.com/Delgan/loguru/issues/534

2.常見(jiàn)錯(cuò)誤2:

File "/home/ronaldinho/xxx/xxx/venv/lib/python3.9/site-packages/loguru/_logger.py", line 939, in add
    handler = Handler(
  File "/home/ronaldinho/xxx/xxx/venv/lib/python3.9/site-packages/loguru/_handler.py", line 86, in __init__
    self._queue = multiprocessing.SimpleQueue()
  File "/home/ronaldinho/.pyenv/versions/3.9.4/lib/python3.9/multiprocessing/context.py", line 113, in SimpleQueue
    return SimpleQueue(ctx=self.get_context())
  File "/home/ronaldinho/.pyenv/versions/3.9.4/lib/python3.9/multiprocessing/queues.py", line 342, in __init__
    self._rlock = ctx.Lock()
  File "/home/ronaldinho/.pyenv/versions/3.9.4/lib/python3.9/multiprocessing/context.py", line 68, in Lock
    return Lock(ctx=self.get_context())
  File "/home/ronaldinho/.pyenv/versions/3.9.4/lib/python3.9/multiprocessing/synchronize.py", line 162, in __init__
  File "/home/ronaldinho/.pyenv/versions/3.9.4/lib/python3.9/multiprocessing/synchronize.py", line 57, in __init__
OSError: [Errno 24] Too many open files

你可以 remove()添加的處理程序,它應(yīng)該釋放文件句柄。 

總之, 諸如此類(lèi)的問(wèn)題都能找到解決方法, 總體來(lái)說(shuō)這個(gè)庫(kù)是非常值得應(yīng)用的, 白看不如一試, 快去coding吧~

到此這篇關(guān)于Python3 Loguru 相見(jiàn)恨晚的輸出日志工具的文章就介紹到這了,更多相關(guān)Python Loguru 輸出日志工具內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Tornado Web Server框架編寫(xiě)簡(jiǎn)易Python服務(wù)器

    Tornado Web Server框架編寫(xiě)簡(jiǎn)易Python服務(wù)器

    這篇文章主要為大家詳細(xì)介紹了Tornado Web Server框架編寫(xiě)簡(jiǎn)易Python服務(wù)器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • python自動(dòng)生成證件號(hào)的方法示例

    python自動(dòng)生成證件號(hào)的方法示例

    這篇文章主要給大家介紹了關(guān)于python自動(dòng)生成證件號(hào)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Python 使用office365郵箱的示例

    Python 使用office365郵箱的示例

    這篇文章主要介紹了Python 使用office365郵箱的示例,幫助大家利用python進(jìn)行高效辦公,感興趣的朋友可以了解下
    2020-10-10
  • Python PyQt5干貨滿(mǎn)滿(mǎn)小項(xiàng)目輕松實(shí)現(xiàn)高效摳圖去背景

    Python PyQt5干貨滿(mǎn)滿(mǎn)小項(xiàng)目輕松實(shí)現(xiàn)高效摳圖去背景

    PyQt5以一套Python模塊的形式來(lái)實(shí)現(xiàn)功能。它包含了超過(guò)620個(gè)類(lèi),600個(gè)方法和函數(shù)。本篇文章手把手帶你用PyQt5輕松實(shí)現(xiàn)圖片扣除背景,大家可以在過(guò)程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • Python?OpenCV實(shí)現(xiàn)圖像傅里葉變換

    Python?OpenCV實(shí)現(xiàn)圖像傅里葉變換

    傅里葉變換,也稱(chēng)作傅立葉變換,表示能將滿(mǎn)足一定條件的某個(gè)函數(shù)表示成三角函數(shù)(正弦和/或余弦函數(shù))或者它們的積分的線(xiàn)性組合。本文將介紹如何通過(guò)OpenCV實(shí)現(xiàn)圖像的傅里葉變換,需要的可以參考一下
    2022-01-01
  • matplotlib繪圖實(shí)例演示標(biāo)記路徑

    matplotlib繪圖實(shí)例演示標(biāo)記路徑

    這篇文章主要介紹了matplotlib繪圖實(shí)例演示標(biāo)記路徑,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • 使用python快速實(shí)現(xiàn)不同機(jī)器間文件夾共享方式

    使用python快速實(shí)現(xiàn)不同機(jī)器間文件夾共享方式

    今天小編就為大家分享一篇使用python快速實(shí)現(xiàn)不同機(jī)器間文件夾共享方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-12-12
  • pytorch 共享參數(shù)的示例

    pytorch 共享參數(shù)的示例

    今天小編就為大家分享一篇pytorch 共享參數(shù)的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-08-08
  • Python內(nèi)置函數(shù)詳談

    Python內(nèi)置函數(shù)詳談

    本篇文章主要介紹了Python內(nèi)置函數(shù)的使用方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-10-10
  • Python多維/嵌套字典數(shù)據(jù)無(wú)限遍歷的實(shí)現(xiàn)

    Python多維/嵌套字典數(shù)據(jù)無(wú)限遍歷的實(shí)現(xiàn)

    下面小編就為大家?guī)?lái)一篇Python多維/嵌套字典數(shù)據(jù)無(wú)限遍歷的實(shí)現(xiàn)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11

最新評(píng)論