ホームページ  >  記事  >  バックエンド開発  >  Python3 Loguru ログ出力ツールの使い方

Python3 Loguru ログ出力ツールの使い方

WBOY
WBOY転載
2023-05-15 15:13:061343ブラウズ

1. はじめに

Python ログ モジュールは、アプリケーションとライブラリの柔軟なイベント ログを実装する関数とクラスを定義します。

プログラム開発プロセス中、多くのプログラムはログを記録する必要があり、ログに含まれる情報には、通常のプログラム アクセス ログが含まれるほか、エラー、警告、その他の情報出力も含まれる場合があります。Python のログ モジュールは標準の機能を提供します。ログ さまざまな形式のログを保存できるインターフェイス。ロギングは、簡単にロギングを使用するための便利な関数のセットを提供します。

Python Logging モジュールを使用する主な利点は、すべての Python モジュールがログに参加できることです。Logging モジュールは、多数の柔軟な関数を提供します。

loguru を使用する理由:

必要なログ情報を出力するのに役立ち、簡単で便利です:

Python を使用してプログラムやスクリプトを作成すると、よく発生する問題が発生します。ログは削除する必要があります。一方では、プログラムに問題が発生した場合のトラブルシューティングに役立ち、他方では、注意が必要な情報を記録するのに役立ちます。
ただし、組み込みのロギング モジュールを使用する場合は、別の初期化やその他の関連作業を実行する必要があります。このモジュールに慣れていない学生にとっては、Handler/Formatter を設定する必要があるなど、まだ少し難しいです。ビジネスの複雑さが増すにつれて、ログ分類、ファイル ストレージ、非同期書き込み、カスタム タイプなどのログ収集の要件が高くなります。

loguru は、Python ロギング ライブラリ用のシンプルで強力なサードパーティです。標準ロガーの注意点に対処する一連の便利な機能を追加することで、Python のロギングの負担を軽減します。

2. loguru をエレガントに使用する

1. loguru をインストールする

pip install loguru

2. 機能と特徴の紹介

には多くの利点があり、より重要なものをリストします。以下にいくつかのポイントがあります:

  • 箱から出してすぐに使用でき、準備は必要ありません

  • 初期化する必要はなく、関数をインポートするだけです。

  • ファイルのロギングとダンプ/保持/圧縮方法が簡単になりました

  • #より洗練された文字列形式の出力

  • #例外はスレッドまたはメイン スレッドでキャッチできます
  • さまざまなレベルのロギング スタイルを設定できます
  • 非同期、スレッド化、およびマルチスレッドをサポートします。プロセスのセキュリティ
  • 遅延評価をサポート
  • スクリプトおよびライブラリと連携
  • 標準と完全な互換性ログ記録
  • #日付と時刻の処理の改善
  • 3. すぐに使用できるため、準備は必要ありません
  • from loguru import logger  
    logger.debug("That's it, beautiful and simple logging!")

不要 初期化後はインポートした関数が使用できるようになるので、問題を解決する方法を尋ねる必要があります。

ハンドラーを追加するにはどうすればよいですか?
  • ログ形式を設定するにはどうすればよいですか (ログのフォーマット)。
  • メッセージをフィルタリングするにはどうすればよいですか?
  • レベル(ログレベル)を設定するにはどうすればよいですか?
  • # add  
    logger.add(sys.stderr, \  
        format="{time} {level} {message}",\  
        filter="my_module",\  
        level="INFO")

    とても簡単ですね~
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(&#39;logs/z_{time}.log&#39;,  
           level=&#39;DEBUG&#39;,  
           format=&#39;{time:YYYY-MM-DD :mm:ss} - {level} - {file} - {line} - {message}&#39;,  
           rotation="10 MB")

8. 非同期、スレッド、マルチプロセスの安全性をサポート

デフォルトでは、ログ情報がロガーに追加されます。スレッドセーフです。ただし、これはマルチプロセスに対して安全ではありません。enqueue パラメータを追加することでログの整合性を確保できます。
  • 非同期タスクでログ記録を使用したい場合は、同じパラメータを使用してそれを確実にすることもできます。そして、complete() を通じて実行が完了するのを待ちます。
  • # 异步写入  
    logger.add("some_file.log", enqueue=True)

    お読みのとおり、非同期で実行するには
  • enqueue=True
のみが必要です

9. 例外の完全な説明

コード内で発生した例外をログに記録するバグ トレースの場合、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() メソッドを使用すると、追加のレコード プロパティを変更することで、ロガー メッセージをコンテキストに組み込むことができます。また、bind() と filter を組み合わせることにより、ロギングをより詳細に制御することもできます。
  • 最後に、patch() メソッドを使用すると、新しいメッセージごとにレコード辞書に動的な値を追加できます。
  • # 序列化为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 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. カスタマイズ可能なレベル

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

13. スクリプトとライブラリに適しています

# 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. 標準ロギングと完全互換

Loguru を組み込みのログ ハンドラーとして使用したいですか?
  • Loguru メッセージを標準ログに送信する必要がありますか?
  • 標準のログ メッセージをインターセプトし、Loguru で要約したいですか?
handler = logging.handlers.SysLogHandler(address=(&#39;localhost&#39;, 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 提供了一个 parse() 方法来帮助处理日志和正则表达式。

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. 通知机制 (邮件告警)

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 框架集成

  • 现在最关键的一个问题是如何兼容别的 logger,比如说 tornado 或者 django 有一些默认的 logger。

  • 经过研究,最好的解决方案是参考官方文档的,完全整合 logging 的工作方式。比如下面将所有的 logging都用 loguru 的 logger 再发送一遍消息。

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[&#39;LOG_PATH&#39;])  
    if not path.exists():  
        path.mkdir(parents=True)  
    log_name = Path(path, &#39;sips.log&#39;)  
    logging.basicConfig(handlers=[InterceptHandler(level=&#39;INFO&#39;)], level=&#39;INFO&#39;)  
    # 配置日志到标准输出流  
    logger.configure(handlers=[{"sink": sys.stderr, "level": &#39;INFO&#39;}])  
    # 配置日志到输出到文件  
    logger.add(log_name, rotation="500 MB", encoding=&#39;utf-8&#39;, colorize=False, level=&#39;INFO&#39;)

18. 要点解析

介绍,主要函数的使用方法和细节 - add()的创建和删除

  • add() 非常重要的参数 sink 参数

  • 具体的实现规范可以参见官方文档

  • 可以实现自定义 Handler 的配置,比如 FileHandler、StreamHandler 等等

  • 可以自行定义输出实现

  • 代表文件路径,会自动创建对应路径的日志文件并将日志输出进去

  • 例如 sys.stderr 或者 open(‘file.log’, ‘w’) 都可以

  • 可以传入一个 file 对象

  • 可以直接传入一个 str 字符串或者 pathlib.Path 对象

  • 可以是一个方法

  • 可以是一个 logging 模块的 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  
):

另外添加 sink 之后我们也可以对其进行删除,相当于重新刷新并写入新的内容。删除的时候根据刚刚 add 方法返回的 id 进行删除即可。可以发现,在调用 remove 方法之后,确实将历史 log 删除了。但实际上这并不是删除,只不过是将 sink 对象移除之后,在这之前的内容不会再输出到日志中,这样我们就可以实现日志的刷新重新写入操作

from loguru import logger  
trace = logger.add(&#39;runtime.log&#39;)  
logger.debug(&#39;this is a debug message&#39;)  
logger.remove(trace)  
logger.debug(&#39;this is another debug message&#39;)

三、总结

我们在开发流程中, 通过日志快速定位问题, 高效率解决问题, 我认为 loguru 能帮你解决不少麻烦, 赶快试试吧~

当然, 使用各种也有不少麻烦, 例如:

1. 常见错误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提交, 避免和服务器文件冲突即可;
当然也不止这个原因引起这个问题, 也可能是三方库(ciscoconfparse)冲突所致.解决办法: https://github.com/Delgan/loguru/issues/534

2.常见错误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()添加的处理程序,它应该释放文件句柄。 


以上がPython3 Loguru ログ出力ツールの使い方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。