Project Icon

loguru

简化Python日志记录的现代化库

Loguru是一个现代化的Python日志记录库,旨在简化日志管理流程。它提供了直观的API,支持文件日志轮转、结构化日志、异常捕获和彩色输出等功能。Loguru无需复杂配置即可使用,适用于脚本和库开发,并与标准日志模块兼容。这个强大而灵活的工具能够帮助开发者提高日志记录效率,优化程序调试和监控过程。

.. raw:: html

<p align="center">
    <a href="#readme">
        <img alt="Loguru标志" src="https://yellow-cdn.veclightyear.com/835a84d5/7dce1a78-d696-42dc-8020-46aa9e076b65.png">
        <!-- 标志致谢: Sambeet from Pixaday -->
        <!-- 标志字体: Comfortaa + Raleway -->
    </a>
</p>
<p align="center">
    <a href="https://pypi.python.org/pypi/loguru"><img alt="Pypi版本" src="https://yellow-cdn.veclightyear.com/835a84d5/7ae80bde-8882-4683-a609-6669f65f143c.svg"></a>
    <a href="https://pypi.python.org/pypi/loguru"><img alt="Python版本" src="https://yellow-cdn.veclightyear.com/835a84d5/a9130a85-9379-4e47-ba28-217dafac5f3e.svg"></a>
    <a href="https://loguru.readthedocs.io/en/stable/index.html"><img alt="文档" src="https://yellow-cdn.veclightyear.com/835a84d5/473223a2-c6a0-487e-8806-ab3c33d25eb6.svg"></a>
    <a href="https://github.com/Delgan/loguru/actions/workflows/tests.yml?query=branch:master"><img alt="构建状态" src="https://img.shields.io/github/actions/workflow/status/Delgan/loguru/tests.yml?branch=master"></a>
    <a href="https://codecov.io/gh/delgan/loguru/branch/master"><img alt="覆盖率" src="https://yellow-cdn.veclightyear.com/835a84d5/d435b1b6-374f-42ac-b943-2bd48d1f9ff4.svg"></a>
    <a href="https://app.codacy.com/gh/Delgan/loguru/dashboard"><img alt="代码质量" src="https://yellow-cdn.veclightyear.com/835a84d5/2e000dbc-c102-40b7-a19c-0a902f31701f.svg"></a>
    <a href="https://github.com/Delgan/loguru/blob/master/LICENSE"><img alt="许可证" src="https://yellow-cdn.veclightyear.com/835a84d5/84408534-7730-4fac-b80d-ccf6031c4dba.svg"></a>
</p>
<p align="center">
    <a href="#readme">
        <img alt="Loguru标志" src="https://yellow-cdn.veclightyear.com/835a84d5/06dd8827-d971-4b3e-a7f6-bb5f1e203939.gif">
    </a>
</p>

=========

Loguru是一个旨在为Python带来愉悦日志记录体验的库。

你是否曾因懒得配置日志记录器而使用print()代替?...我曾经如此,然而日志记录对每个应用程序都至关重要,并且能够简化调试过程。使用Loguru,你再也没有理由不从一开始就使用日志记录,它就像from loguru import logger这样简单。

此外,这个库旨在通过添加一系列有用的功能来解决标准日志记录器的缺点,从而使Python日志记录不那么痛苦。在应用程序中使用日志应该是一种自动化行为,Loguru试图使其既愉快又强大。

.. end-of-readme-intro

安装

::

pip install loguru

特性

  • 开箱即用,无需样板代码_
  • 无Handler、无Formatter、无Filter:一个函数统治所有_
  • 更简单的文件日志记录,支持轮转/保留/压缩_
  • 使用大括号风格的现代字符串格式化_
  • 在线程或主程序中捕获异常_
  • 带颜色的美观日志输出_
  • 异步、线程安全、多进程安全_
  • 完全描述性的异常_
  • 根据需要进行结构化日志记录_
  • 昂贵函数的惰性求值_
  • 可自定义的日志级别_
  • 更好的日期时间处理_
  • 适用于脚本和库_
  • 与标准日志完全兼容_
  • 通过环境变量个性化默认设置_
  • 便捷的解析器_
  • 详尽的通知器_
  • |strike| 比内置日志记录快10倍_ |/strike|

功能概览

.. highlight:: python3

.. |logger| replace:: logger .. _logger: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger

.. |add| replace:: add() .. _add: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.add

.. |remove| replace:: remove() .. _remove: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.remove

.. |complete| replace:: complete() .. _complete: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.complete

.. |catch| replace:: catch() .. _catch: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.catch

.. |bind| replace:: bind() .. _bind: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.bind

.. |contextualize| replace:: contextualize() .. _contextualize: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.contextualize

.. |patch| replace:: patch() .. _patch: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.patch

.. |opt| replace:: opt() .. _opt: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.opt

.. |trace| replace:: trace() .. _trace: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.trace

.. |success| replace:: success() .. _success: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.success

.. |level| replace:: level() .. _level: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.level

.. |configure| replace:: configure() .. _configure: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.configure

.. |disable| replace:: disable() .. _disable: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.disable

.. |enable| replace:: enable() .. _enable: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.enable

.. |parse| replace:: parse() .. _parse: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.parse

.. _sinks: https://loguru.readthedocs.io/en/stable/api/logger.html#sink .. _record dict: https://loguru.readthedocs.io/en/stable/api/logger.html#record .. _log messages: https://loguru.readthedocs.io/en/stable/api/logger.html#message .. _easily configurable: https://loguru.readthedocs.io/en/stable/api/logger.html#file .. _markup tags: https://loguru.readthedocs.io/en/stable/api/logger.html#color .. _fixes it: https://loguru.readthedocs.io/en/stable/api/logger.html#time .. _No problem: https://loguru.readthedocs.io/en/stable/api/logger.html#env .. _logging levels: https://loguru.readthedocs.io/en/stable/api/logger.html#levels

.. |better_exceptions| replace:: better_exceptions .. _better_exceptions: https://github.com/Qix-/better-exceptions

.. |loguru-config| replace:: loguru-config .. _loguru-config: https://github.com/erezinman/loguru-config

.. |notifiers| replace:: notifiers .. _notifiers: https://github.com/notifiers/notifiers

开箱即用,无需样板代码 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Loguru的主要理念是有且仅有一个 |logger|_。

为了方便起见,它被预先配置并默认输出到stderr(但这完全可以配置)。 ::

from loguru import logger

logger.debug("就是这样,简洁优雅的日志记录!")

|logger|_ 只是一个将日志消息分发给配置好的处理程序的接口。很简单,对吧?

无处理程序,无格式化器,无过滤器:一个函数掌控一切 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

如何添加处理程序?如何设置日志格式?如何过滤消息?如何设置级别?

一个答案:使用 |add|_ 函数。

::

logger.add(sys.stderr, format="{time} {level} {message}", filter="my_module", level="INFO")

这个函数应该用于注册 sinks_ ,它们负责管理带有 record dict_ 上下文的 log messages_ 。sink可以有多种形式:简单的函数、字符串路径、类文件对象、协程函数或内置的Handler。

注意,你也可以使用添加时返回的标识符通过 |remove|_ 移除之前添加的处理程序。如果你想替换默认的 stderr 处理程序,这特别有用:只需调用 logger.remove() 重新开始。

更简便的文件日志记录,支持轮转/保留/压缩 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

如果你想将日志消息发送到文件,只需将字符串路径作为sink即可。为方便起见,它还可以自动添加时间戳::

logger.add("file_{time}.log")

如果你需要轮转日志、删除旧日志或在关闭时压缩文件,这也很容易配置。

::

logger.add("file_1.log", rotation="500 MB")    # 自动轮转过大的文件
logger.add("file_2.log", rotation="12:00")     # 每天中午创建新文件
logger.add("file_3.log", rotation="1 week")    # 文件太旧时进行轮转

logger.add("file_X.log", retention="10 days")  # 一段时间后清理

logger.add("file_Y.log", compression="zip")    # 节省一些珍贵的空间

使用大括号风格的现代字符串格式化 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Loguru 更倾向于使用更优雅强大的 {} 格式化而非 %,日志函数实际上等同于 str.format()

::

logger.info("如果你使用的是Python {}, 当然应该首选{feature}!", 3.6, feature="f-字符串")

捕获线程或主程序中的异常 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

你是否遇到过程序意外崩溃但日志文件中却没有任何记录?你是否注意到线程中发生的异常没有被记录?使用 |catch|_ 装饰器/上下文管理器可以解决这个问题,它确保任何错误都能正确传播到 |logger|_ 。

::

@logger.catch
def my_function(x, y, z):
    # 出错了?无论如何都会被捕获!
    return 1 / (x + y + z)

带颜色的美观日志 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

如果你的终端支持,Loguru 会自动为日志添加颜色。你可以在sink格式中使用 markup tags_ 来定义你喜欢的样式。

::

logger.add(sys.stdout, colorize=True, format="<green>{time}</green> <level>{message}</level>")

异步、线程安全、多进程安全 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

默认情况下,添加到 |logger|_ 的所有sink都是线程安全的。它们不是多进程安全的,但你可以使用 enqueue 参数来确保日志的完整性。如果你想要异步日志记录,也可以使用这个参数。

::

logger.add("somefile.log", enqueue=True)

作为sink的协程函数也受支持,应该使用 |complete|_ 来等待。

完整描述的异常 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

记录代码中发生的异常对于跟踪bug很重要,但如果你不知道为什么失败,这就没什么用。Loguru 通过允许显示整个堆栈跟踪(包括变量值)来帮助你识别问题(感谢 |better_exceptions|_ !)。

代码::

# 注意,"diagnose=True"是默认值,在生产环境中可能会泄露敏感数据
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("什么?!")

nested(0)

会产生以下结果:

.. code-block:: none

2018-07-17 01:38:43.975 | ERROR    | __main__:nested:10 - 什么?!
Traceback (most recent call last):

  File "test.py", line 12, in <module>
    nested(0)
    └ <function nested at 0x7f5c755322f0>

> File "test.py", line 8, in nested
    func(5, c)
    │       └ 0
    └ <function func at 0x7f5c79fc2e18>

  File "test.py", line 4, in func
    return a / b
           │   └ 0
           └ 5

ZeroDivisionError: division by zero

注意,由于无法获取帧数据,此功能在默认的Python REPL中不起作用。

另请参阅: 使用Loguru时的安全考虑 <https://loguru.readthedocs.io/en/stable/resources/recipes.html#security-considerations-when-using-loguru>_.

根据需要进行结构化日志记录 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

想要序列化你的日志以便于解析或传递?使用 serialize 参数,每条日志消息都会在发送到配置的sink之前转换为JSON字符串。

::

logger.add(custom_sink_function, serialize=True)

使用 |bind|_ 可以通过修改 extra 记录属性来为你的logger消息添加上下文。

::

logger.add("file.log", format="{extra[ip]} {extra[user]} {message}")
context_logger = logger.bind(ip="192.168.0.1", user="someone")
context_logger.info("轻松为你的logger添加上下文")
context_logger.bind(user="someone_else").info("内联绑定额外属性")
context_logger.info("在格式化时使用kwargs添加上下文: {user}", user="anybody")

可以使用 |contextualize|_ 临时修改上下文本地状态:

::

with logger.contextualize(task=task_id):
    do_something()
    logger.info("任务结束")

你还可以通过结合使用 |bind|_ 和 filter 来对日志进行更精细的控制:

::

logger.add("special.log", filter=lambda record: "special" in record["extra"])
logger.debug("此消息不会记录到文件中")
logger.bind(special=True).info("但是,这条消息会记录到文件中!")

最后,|patch|_ 方法允许将动态值附加到每条新消息的记录字典中:

::

logger.add(sys.stderr, format="{extra[utc]} {message}")
logger = logger.patch(lambda record: record["extra"].update(utc=datetime.utcnow()))

昂贵函数的延迟求值 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

有时你想记录详细信息而不影响生产环境的性能,你可以使用 |opt|_ 方法来实现这一点。

::

logger.opt(lazy=True).debug("如果sink级别 <= DEBUG: {x}", x=lambda: expensive_function(2**64))

# 顺便说一下,"opt()"有多种用途
logger.opt(exception=True).info("错误堆栈跟踪添加到日志消息中(也接受元组)")
logger.opt(colors=True).info("每条消息的<blue>颜色</blue>")
logger.opt(record=True).info("显示记录中的值(例如 {record[thread]})")
logger.opt(raw=True).info("绕过sink格式化\n")
logger.opt(depth=1).info("使用父栈上下文(在包装函数中很有用)")
logger.opt(capture=False).info("关键字参数不会添加到{dest}字典中", dest="extra")

可自定义的级别 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Loguru 带有所有标准 logging levels_ ,并额外添加了 |trace|_ 和 |success|_ 。需要更多级别?那么,只需使用 |level|_ 函数创建即可。

::

new_level = logger.level("SNAKY", no=38, color="<yellow>", icon="🐍")

logger.log("SNAKY", "开始吧!")

更好的日期时间处理 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 标准日志记录的参数过于臃肿,如 datefmtmsecs%(asctime)s%(created)s,还有不带时区信息的原生日期时间,以及不直观的格式化等。Loguru 解决了这些问题:

::

logger.add("file.log", format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}")

适用于脚本和库 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

在脚本中使用日志记录器很简单,你可以在开始时进行配置。在库中使用 Loguru 时,记住永远不要调用 |add|,而是使用 |disable|,这样日志函数就会变成无操作。如果开发者希望查看你的库的日志,他们可以再次 |enable|_ 它。

::

# 对于脚本
config = {
    "handlers": [
        {"sink": sys.stdout, "format": "{time} - {message}"},
        {"sink": "file.log", "serialize": True},
    ],
    "extra": {"user": "someone"}
}
logger.configure(**config)

# 对于库,应该是你的库的 `__name__`
logger.disable("my_library")
logger.info("无论添加了什么接收器,这条消息都不会显示")

# 在你的应用程序中,启用库中的日志记录器
logger.enable("my_library")
logger.info("这条消息会传播到接收器")

为了更加方便,你还可以使用 |loguru-config|_ 库直接从配置文件设置 logger

完全兼容标准日志记录 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

想要使用内置的日志记录 Handler 作为 Loguru 的接收器吗?

::

handler = logging.handlers.SysLogHandler(address=('localhost', 514))
logger.add(handler)

需要将 Loguru 消息传播到标准 logging 吗?

::

class PropagateHandler(logging.Handler):
    def emit(self, record: logging.LogRecord) -> None:
        logging.getLogger(record.name).handle(record)

logger.add(PropagateHandler(), format="{message}")

想要拦截标准 logging 消息并发送到你的 Loguru 接收器吗?

::

class InterceptHandler(logging.Handler):
    def emit(self, record: logging.LogRecord) -> None:
        # 获取对应的 Loguru 级别(如果存在)
        level: str | int
        try:
            level = logger.level(record.levelname).name
        except ValueError:
            level = record.levelno

        # 找到产生日志消息的调用者
        frame, depth = inspect.currentframe(), 0
        while frame and (depth == 0 or frame.f_code.co_filename == logging.__file__):
            frame = frame.f_back
            depth += 1

        logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())

logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)

通过环境变量个性化默认设置 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

不喜欢默认的日志记录器格式?想要更改 DEBUG 的颜色?没问题:

::

# Linux / OSX
export LOGURU_FORMAT="{time} | <lvl>{message}</lvl>"

# Windows
setx LOGURU_DEBUG_COLOR "<green>"

便捷的解析器 ^^^^^^^^^^^^^^^^^

从生成的日志中提取特定信息通常很有用,这就是为什么 Loguru 提供了 |parse|_ 方法,它有助于处理日志和正则表达式。

::

pattern = r"(?P<time>.*) - (?P<level>[0-9]+) - (?P<message>.*)"  # 带命名组的正则表达式
caster_dict = dict(time=dateutil.parser.parse, level=int)        # 转换匹配组

for groups in logger.parse("file.log", pattern, cast=caster_dict):
    print("解析结果:", groups)
    # {"level": 30, "message": "日志示例", "time": datetime(2018, 12, 09, 11, 23, 55)}

全面的通知器 ^^^^^^^^^^^^^^^^^^^

Loguru 可以轻松与优秀的 |notifiers|_ 库(需要单独安装)结合使用,在程序意外失败时接收电子邮件,或发送其他多种类型的通知。

::

import notifiers

params = {
    "username": "you@gmail.com",
    "password": "abc123",
    "to": "dest@gmail.com"
}

# 发送单个通知
notifier = notifiers.get_notifier("gmail")
notifier.notify(message="应用程序正在运行!", **params)

# 对每条错误消息发出警报
from notifiers.logging import NotificationHandler

handler = NotificationHandler("gmail", defaults=params)
logger.add(handler, level="ERROR")

|strike|

比内置日志记录快10倍 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

|/strike|

尽管在大多数情况下日志记录对性能的影响可以忽略不计,但零成本的日志记录器可以让我们在任何地方使用它而无需太多顾虑。在即将发布的版本中,Loguru 的关键功能将用 C 语言实现,以达到最高的速度。

文档

  • API 参考 <https://loguru.readthedocs.io/en/stable/api/logger.html>_
  • 帮助与指南 <https://loguru.readthedocs.io/en/stable/resources.html>_
  • 类型提示 <https://loguru.readthedocs.io/en/stable/api/type_hints.html>_
  • 贡献指南 <https://loguru.readthedocs.io/en/stable/project/contributing.html>_
  • 许可证 <https://loguru.readthedocs.io/en/stable/project/license.html>_
  • 更新日志 <https://loguru.readthedocs.io/en/stable/project/changelog.html>_
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号