Loguru的说明书

本文是loguru的doc的阅读笔记,原文链接为:原文链接

loguru 是一个替代 Python logging 的第三方库:简单易用且功能强大。

Loguru 仅使用一个全局 logger 实例

  • 在整个进程中,无需创建多个 logger 实例,而是使用一个预配置的单一 logger,这与Python标准的 logging 库的使用方式不同。
  • 使用一个全局的 logger 可以简化配置,方便使用,您可以在任何地方导入 logger 以直接使用,同时确保日志的格式和处理方法在整个进程中保持一致。
  • 尽管只有一个全局的 logger 对象,但 loguru 允许用户使用 bind 来添加自定义的上下文属性,并提供了 filter 来区分不同的日志源,并进行不同的处理。

add() 代替了 handlersformattersfilters

add() 方法允许进行以下设置:

  • 输出目标(sink):可以是文件名、文件对象、标准输出、自定义流、远程服务器或数据库。
  • 日志格式:可以自定义日志的显示格式。
  • 日志级别:您可以全局设置,或为每个输出目标设置单独的级别。
  • 过滤器:可以是一个函数或条件表达式,用于决定是否输出日志。
  • 文件的压缩和大小限制:根据时间和文件大小设置自动覆盖轮转,并能自动压缩日志文件。
logger.add(sys.stderr, format="{time} {level} {message}", filter="my_module", level="INFO")
logger.add("file_{time}.log")
logger.add("file_1.log", rotation="500 MB")    # Automatically rotate too big file
logger.add("file_2.log", rotation="12:00")     # New file is created each day at noon
logger.add("file_3.log", rotation="1 week")    # Once the file is too old, it's rotated
logger.add("file_X.log", retention="10 days")  # Cleanup after some time
logger.add("file_Y.log", compression="zip")    # Save some loved space

加强的文本格式化

  • 可以直接在日志字符串中使用 {} 来插入变量或者表达式。
  • 日志格式支持富文本颜色编码
from loguru import logger
score = 100.0
user = {'name': 'Ben', 'age': 18}
logger.info("{}, {s}, {name} and {age}", score, s=score, **user)
logger.info("If you're using Python {}, prefer {feature} of course!", 3.9, feature="f-strings")# Pretty logging with color
logger.add(sys.stdout, colorize=True, format="<green>{time}</green> <level>{message}</level>")
  • 消息的文本和值紧密相连,便于阅读。
  • 花括号内支持表达式,具有灵活性。
  • loguru 对表达式的求值采用延迟计算,若不满足记录条件,则不进行求值。

用 catch 记录未捕获的异常

  • loguru 中,catch 是一个装饰器,它可以应用于一个函数上,用以捕获该函数抛出的异常。
  • loguru 中,catch 可以作为上下文管理器,与 with 一起用于捕获抛出的异常。
from loguru import logger
@logger.catch
def thread_function_with_exeption():raise ValueError('An Exeption!')def foo():with logger.catch():raise ValueError('An Exception!')

线程安全、多进程、异步日志记录

  • loguru 中,sink 是线程安全的。
  • 在多进程环境中,如果多个进程尝试写入同一个日志文件,可能会导致数据损坏。为了避免这种情况,可以在使用 add 方法时加上 enqueue=True 参数,这将使得日志消息通过消息队列进行管理。
  • 在高性能应用中,使用 enqueue=True 可以让消息处理在后台线程中执行,从而减少对主应用性能的影响。
  • 如果你的 sink 是一个协程函数,例如,你添加了一个协程来将日志保存到远程服务或数据库,记得在最后调用 loguru.complete() 以确保所有的异步日志任务已完成。
import asyncio
from loguru import loggerasync def async_sink(message):await async_operation(message)logger.add(async_sink)async def main():logger.info('my message')await logger.complete()asyncio.run(main())

完整的异常描述

  • 能够完整地记录异常信息,包括堆栈跟踪(stack trace)和触发异常时的变量值
# Caution, "diagnose=True" is the default and may leak sensitive data in prod
logger.add("out.log", backtrace=True, diagnose=True)def func(a, b):return a / bdef nested(c):try:func(5, c)except ZeroDivisionError:logger.exception("What?!")nested(0)> 2018-07-17 01:38:43.975 | ERROR    | __main__:nested:10 - What?!
> 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

结构化和序列化

  • 将日志记录序列化为结构化的JSON,以便传递给其他模块进行解析。
logger.add(sys.stdout, serialize=True)
logger.info('Logger initialized')> {
>   "text": "2024-04-28 15:13:22.256 | INFO     | __main__:<module>:32 - Logger initialized\\n",
>   "record": {
>     "elapsed": {
>       "repr": "0:00:00.244809",
>       "seconds": 0.244809
>     },
>     "exception": null,
>     "extra": {},
>     "file": {
>       "name": "my_test.py",
>       "path": ".../my_test.py"
>     },
>     "function": "<module>",
>     "level": {
>       "icon": "ℹ️",
>       "name": "INFO",
>       "no": 20
>     },
>     "line": 32,
>     "message": "Logger initialized",
>     "module": "my_test",
>     "name": "__main__",
>     "process": {
>       "id": 66324,
>       "name": "MainProcess"
>     },
>     "thread": {
>       "id": 7993007168,
>       "name": "MainThread"
>     },
>     "time": {
>       "repr": "2024-04-28 15:13:22.256298+08:00",
>       "timestamp": 1714288402.256298
>     }
>   }
> }

logger 的上下文管理

  • 可以为日志消息添加额外的上下文信息,这等同于为每一条相关的日志消息增加了一些 Record 属性,这些属性会与日志一起被记录。
logger.add("file.log", format="{extra[ip]} {extra[user]} {message}")
context_logger = logger.bind(ip="192.168.0.1", 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")
  • 通过结合使用 bind()filter,您可以更精确地控制日志输出。
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}")
logger = logger.patch(lambda record: record["extra"].update(utc=datetime.utcnow()))
  • 使用 contextualize() 方法临时修改上下文
with logger.contextualize(task=task_id):...logger.info("End of task")``

# 定义一个函数来创建格式化字符串,需要包含特定的 extra 字段
def custom_format(record):task_value = record["extra"].get("task", "N/A")  # 从extra获取task字段,如果没有则返回"N/A"return f"{record['time']} {record['level']} {record['message']} | task={task_value}"logger.add(sink_obj, format=custom_format, level="INFO")task_id = ...with logger.contextualize(task=task_id):logger.info("End of task")

logger.opt() 方法

  • logger.opt(lazy=True):只有 message 需要输出的时候才去对其求值,这样可以避免一些计算代价比较高的运算。
  • logger.opt(exception=True):在日志消息中添加异常堆栈跟踪。
  • logger.opt(depth=1):改变堆栈跟踪深度
  • logger.opt(color=True):在日志消息中使用颜色。
  • logger.opt(record=True):在日志消息记录线程 ID 等各种属性。
  • logger.opt(raw=True):绕过日志的格式化器直接输出。
  • logger.opt(capture=False):是否将关键字参数自动添加到日志记录的 extra

def my_decorator(func):def wrapper(*args, **kwargs):logger.info(f"Calling function: {func.__name__}")logger.opt(depth=1).info(f"Calling function: {func.__name__}")result = func(*args, **kwargs)return resultreturn wrapper@my_decorator
def some_function():logger.info("Inside some_function")some_function()
2024-05-06 15:06:25.984 | INFO     | __main__:wrapper:5 - Calling function: some_function
2024-05-06 15:06:25.984 | INFO     | __main__:<module>:15 - Calling function: some_function
2024-05-06 15:06:25.985 | INFO     | __main__:some_function:13 - Inside some_function

loguru 自定义日志级别

  • 创建一个新的日志级别:new_level = logger.level("SNAKY", no=38, color="<yellow>", icon="🐍")
    • "SNAKY": 新日志级别的名称。
    • no=38: 日志级别的数值。日志级别的数值很重要,因为它决定了日志消息的重要性。数值越低,级别越高。例如,标准的 DEBUG 级别是 10,而 CRITICAL 是 50。
    • color="<yellow>": 在支持颜色的终端中,此级别的日志消息将以黄色显示。
    • icon="🐍": 这个级别的日志消息将以蛇形图标(🐍)作为前缀。
  • 使用自定义的日志级别:logger.log("SNAKY", "Here we go!")
  • loguru 增加了两个非标准的级别:tracesuccess
    • trace 级别在日志级别层次中处于最低端,低于 DEBUG 级别,用于输出极其详细的执行信息的情况,比如复杂的问题排查(troubleshooting)和调试,可以使用它来记录函数的详细调用参数、返回值或是中间计算的状态。
    • success 级别用于记录操作成功完成的情况,高于 INFO 级别,但低于 WARNING 级别,为成功事件提供了一个明确的记录点。例如,在一个长时间运行的数据处理任务成功完成后,或是在用户完成关键的账户设置步骤后。

日期的简化和优化

  • 在传统的 Python logging 模块中,处理日期和时间往往需要手动设置多个参数,如 datefmt、在格式字符串中使用 %(asctime)s%(created)s 等,而且默认、间戳不带时区信息(naive datetimes)。
  • loguru 可以直接在日志格式字符串中指定时间的格式 logger.add("file.log", format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}")
  • loguru 默认支持包含时区信息的日期和时间

通过 configure() 配置 loguru

  • 通过脚本配置 loguru
import sys
from loguru import loggerconfig = {"handlers": [{"sink": sys.stdout, "format": "{time} - {message}"},{"sink": "file.log", "serialize": True},],"extra": {"user": "someone"}
}
logger.configure(**config)
  • 通过 loguru-config 库加在配置文件
    • https://github.com/erezinman/loguru-config
  • 禁用/启用 Python 库中的 loguru
    • Library 应该先调用 configure(),岁后 disable() loguru
# For libraries, should be your library's `__name__`
import mylibmy_lib_name = mylib.__name__logger.disable(my_lib_name)
logger.info("No matter added sinks, this message is not displayed")# In your application, enable the logger in the `library`
logger.enable(my_lib_name)
logger.info("This message however is propagated to the sinks")

通过环境变量修改默认配置

  • 完整的环境变量列表:https://github.com/Delgan/loguru/blob/master/loguru/_defaults.py
# Linux / OSX
export LOGURU_FORMAT="{time} | <lvl>{message}</lvl>"# Windows
setx LOGURU_DEBUG_COLOR "<green>"

loguru 自带的 parse

  • loguru 提供了内置 parse() 用来解析日志文件,获取信息
# time: 匹配任何字符,直到遇到 " - "
# level: 匹配一个或多个数字
# message: 匹配任何字符直到行末
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("Parsed:", groups)# {"level": 30, "message": "Log example", "time": datetime(2018, 12, 09, 11, 23, 55)}

loguru 和内置 logging 完全兼容

  • 可以直接 add 内置的 handler
import logging
from loguru import loggerhandler = logging.handlers.SysLogHandler(address=('localhost', 514))
logger.add(handler)
  • loguru 消息传递到内置 logging
import logging
from loguru import loggerclass 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:level: str | int# 尝试获取与标准 logging 等级相对应的 Loguru 日志等级try:level = logger.level(record.levelname).nameexcept ValueError:# 如果找不到对应的 Loguru 等级,则使用原始的数字等级level = record.levelno# 探测调用日志的代码位置frame, depth = inspect.currentframe(), 0while frame and (depth == 0 or frame.f_code.co_filename == logging.__file__):frame = frame.f_backdepth += 1# 使用 Loguru 记录日志信息,保持调用栈的深度和异常信息logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)
  • loguru 拦截 logging 的消息需要的信息包括 levelframe 深度、消息记录。
  • level: str | int 是类型提示,字符串或者整数
  • 先试图将 level name 转为对应的 level,如果失败则使用 int 型的 level 数值
  • 从当前的 frame 通过 f_back 追溯到调用 logging 的具体代码位置
  • opt() 函数设置 loguru
  • basicConfig 设置全局转发
  • level 为 0 会转发所有 level 的消息
  • force 确保无论之前日志系统如何配置,都将应用我们的配置,使得 InterceptHandler 生效

notifiers 库结合使用

  • notifiers 库需要事先单独安装
import notifiersparams = {"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 NotificationHandlerhandler = NotificationHandler("gmail", defaults=params)
logger.add(handler, level="ERROR")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/7078.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

抖音小店如何快速出单?内行人闭口不提的诀窍,一篇全曝光!

哈喽~我是电商月月 新手做抖店不成功&#xff0c;最大的问题就是不懂技巧&#xff0c;不懂规则&#xff0c;不懂玩法&#xff0c;你基础事项&#xff0c;思维方向都没选好&#xff0c;再怎么努力也别想出单 看下去&#xff0c;新手在开店后不要着急选品&#xff0c;先把这些问…

AI热潮开始退去,财务压力迫使多家硅谷明星初创公司选择退出

曾风光无限的Stability AI已重组并削减业务规模&#xff0c;Inflection AI更是关闭业务并基本并入微软。 5月4日消息&#xff0c;国外媒体日前撰文指出&#xff0c;人工智能的热潮已开始逐渐褪去。初创公司想要同微软、谷歌等科技巨头在人工智能领域一决高下&#xff0c;门槛已…

shell脚本中的特殊变量

在Shell脚本中&#xff0c;有一些特殊变量具有特定的含义和用途。以下是示例和一些常见的特殊变量及其区别&#xff1a; bash test.sh 参数1 参数2 参数3.... 1. $0&#xff1a;表示当前脚本的文件名。 2. $1, $2, ...&#xff1a;表示脚本接收的参数&#xff0c;$1表示第…

供应链|经典论文解读:(s,S) 策略在动态库存下的最优性

文章考虑了具有订购成本&#xff08;由单位成本加上重新订购成本组成&#xff09;的动态库存问题。具体而言&#xff0c;对于每个时期&#xff0c;系统在中期开始是做出一系列采购决策——这些采购有助于库存的积累&#xff0c;并在随后的周期被需求所消耗。每时期系统会产生各…

【SQL】ACID事务与隔离级别

数据库事务 数据库事务具有ACID这4个特性&#xff1a; A&#xff1a;Atomicity&#xff0c;原子性&#xff0c;将所有SQL作为原子工作单元执行&#xff0c;要么全部执行&#xff0c;要么全部不执行&#xff1b;C&#xff1a;Consistency&#xff0c;一致性&#xff0c;事务完…

04-18 周四 为LLM_inference项目配置GitHub CI过程记录

04-18 周四 为LLM_inference项目配置GitHub CI过程记录 时间版本修改人描述2024年4月18日10:30:13V0.1宋全恒新建文档 简介和相关文档 04-15 周一 GitHub仓库CI服务器配置过程文档actions-runner 是托管与GitHub上的仓库&#xff0c;下载最新的客户端程序即可。self hosted r…

一个年薪30w软件测试员的职业规划,献给还在迷茫中的朋友

先抛出一个观点 &#xff0c; 那些&#xff0c;担心30岁后&#xff0c;35岁后&#xff0c;40岁后&#xff0c;无路可走的&#xff1b;基本属于能力不够、或者思维太局限 。 总之&#xff0c;瞎担心 / 不长进 。 具体&#xff0c;见下面正文 。 曾经&#xff0c;在16年&#xff…

AI技术赋能下的视频监控方案是如何解决新能源汽车充电难问题的?

一、方案背景 刚刚结束的第十八届北京车展异常火爆&#xff0c;其中一组与汽车有关的数字让人格外关注。根据乘联会2024年4月19日公布的最新数据&#xff0c;全国乘用车市场零售达到51.6万辆&#xff0c;其中新能源车的销量约为26万辆&#xff0c;市场渗透率达到50.39%。 这意味…

国产化操作系统都有哪些?如何选择?

国产化操作系统主要包括以下几种&#xff1a; 深度Linux&#xff08;Deepin&#xff09;&#xff1a;基于Linux内核&#xff0c;已具备相对完善的产品体系&#xff0c;并广泛应用于关键领域。统信UOS&#xff08;统一操作系统&#xff09;&#xff1a;支持多种国产CPU平台&…

音视频开发4 FFmpeg windows 环境搭建,QT 安装,动态库的搜索路径

FFmpeg 为了让所有平台的开发者都能够学习到音视频开发的通用技术&#xff0c;本教程主要讲解跨平台的音视频开发库FFmpeg。其实只要你掌握了FFmpeg&#xff0c;也可以很快上手其他音视频开发库&#xff0c;因为底层原理都是一样的&#xff0c;你最终操作的都是一样的数据&…

【第10章】spring-mvc转发和重定向

文章目录 前言一、准备二、转发1. 视图解析器(推荐)2. 关键字(forward)3. request 三、重定向1.关键字(redirect)2. HttpServletResponse 四、区别总结 前言 前面介绍了视图解析器的使用,但是对我们原有转发和重定向有影响,接下来我们通过案例,来使用学习转发和重定向的用法。…

ComfyUI 基础教程(十四):ComfyUI中4种实现局部重绘方法

在ComfyUI中有多种方式可以实现局部重绘,简单的方式是使用VAE内补编码器进行局部重绘,也可以用Fooocus inpaint进行局部重绘,还可以用controlNet的inpaint模型进行局部重绘,以及使用Clip seg蒙版插件! 本篇介绍使用VAE內补编码器进行局部重绘的方法。 1、VAE内补编码器 局…

《架构风清扬-Java面试系列第28讲》聊聊SynchronousQueue的使用及适合场景

SynchronousQueue是BlockingQueue接口的一个实现类之一 这个属于基础性问题&#xff0c;老规矩&#xff0c;我们将从使用场景和代码示例来进行讲解 来&#xff0c;思考片刻&#xff0c;给出你的答案 1&#xff0c;使用场景 实现&#xff1a;特殊的无缓冲队列&#xff0c;每一个…

帆软报表9.0连接达梦数据库

一、将驱动复制到帆软安装目录下 二、配置数据库连接 注意&#xff1a;dm.jdbc.driver.DmDriver是直接在文本框输入的 进行以上两部就能连接达梦数据库了

深度学习的核心数学知识点

深度学习的数学知识点包括但不限于以下几个方面&#xff1a; 线性代数&#xff1a; 标量、向量、矩阵和张量&#xff1a;这些是线性代数的基础元素。标量是一个单独的数&#xff0c;向量是有序的数字列表&#xff0c;矩阵是二维数字网格&#xff0c;而张量则是更高维度的数据容…

揭秘!如何利用自动化工具提升抖音推广效果

亲爱的读者朋友们&#xff0c;你是否在为抖音的推广效果而苦恼&#xff1f;看着别人家的视频轻松获得大量曝光&#xff0c;你是否也心生羡慕&#xff1f;今天&#xff0c;我们就来分享一个秘密武器&#xff0c;让你轻松提升抖音推广效果&#xff01; 首先&#xff0c;让我们来了…

开发环境待

一 web开发环境搭建 1 web开发环境概述 所谓web开发,指的就是从网页中向后端程序发送请求.与后端程序进行交互. 流程图: 1,Web服务器是指驻留于因特网上某种类型计算机的程序. 2, 可以向浏览器等Web客户端提供文档&#xff0c;也可以放置网站文件&#xff0c;让全世界 浏览…

微信答题活动怎么做_智慧与惊喜的碰撞

在这个信息爆炸的时代&#xff0c;如何吸引用户的眼球&#xff0c;让他们在众多品牌中驻足停留&#xff1f;答案或许就藏在一次别开生面的微信答题活动中。今天&#xff0c;就让我们一起走进这场以智慧与惊喜为主题的微信答题狂欢夜&#xff0c;感受其带来的独特魅力。 工具/原…

AI预测福彩3D第10套算法实战化赚米验证第2弹2024年5月6日第2次测试

由于今天白天事情比较多&#xff0c;回来比较晚了&#xff0c;趁着还未开奖&#xff0c;赶紧把预测结果发出来吧~今天是第2次测试~ 2024年5月6日福彩3D预测结果 6-7码定位方案如下&#xff1a; 百位&#xff1a;3、4、1、7、8、9 十位&#xff1a;4、5、3、7、8、9 个位&#x…

JS基础:输出信息的5种方式详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端基础路线”&#xff0c;可获取完整web基础…