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 logger

async 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 / b

def 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 result
    return 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 logger

config = {
    "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 mylib

my_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 logger

handler = logging.handlers.SysLogHandler(address=('localhost', 514))
logger.add(handler)
  • loguru 消息传递到内置 logging
import logging
from loguru import logger

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:
        level: str | int
        # 尝试获取与标准 logging 等级相对应的 Loguru 日志等级
        try:
            level = logger.level(record.levelname).name
        except ValueError:
		    # 如果找不到对应的 Loguru 等级,则使用原始的数字等级
            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
		# 使用 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 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")

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

武汉星起航:跨境电商领域国际竞争力卓越,引领行业再上新台阶

在全球化浪潮的推动下&#xff0c;跨境电商行业日益成为各国经济交流与合作的重要桥梁。武汉星起航电子商务有限公司&#xff0c;作为跨境电商领域的佼佼者&#xff0c;凭借其深厚的行业经验和前瞻性的战略视野&#xff0c;在国际市场上展现出强大的竞争力&#xff0c;为行业的…

优化理论复习——(二)

本篇主要介绍一下LP问题及其相关的解法和示例&#xff0c;主要是记住相关的方法和结论即可&#xff0c;不要求证明。 方法主要是单纯形法&#xff0c;同时对于初始基可行解确定方面使用了大M法和二阶段法。主体都是关于单纯形法的。 首先认识一下线性规划的一般问题形式&#x…

报错,java: 程序包sun.misc不存在

错误描述 down下来一个项目&#xff0c;编译的时候报错&#xff0c;提示sun.misc包不存在&#xff0c;通过百度得知&#xff0c;原来这是jdk8中的jar包&#xff0c;在后来的版本中被移除了&#xff08;我用的jdk11&#xff0c;没有这个包&#xff09; 结局方法 1.更换jdk版本&…

知识库工具:付费的HelpLook AI知识库比免费的牵牛易帮好在哪里

在知识管理的领域中&#xff0c;选择合适的知识库工具对于企业来说很重要。市面上有很多知识库产品&#xff0c;有付费的和免费的&#xff0c;但是还是有很多企业会选择使用付费的&#xff0c;而不是免费的。这是为什么呢&#xff1f;这就是今天要探讨的问题&#xff0c;下面就…

vs配置cplex12.10

1.创建c空项目 2.修改运行环境 为release以及x64 3.创建cpp文件 4.鼠标右键点击项目中的属性 5.点击c/c&#xff0c;点击第一项常规&#xff0c;配置附加库目录 5.添加文件索引&#xff0c;主要用于把路径导进来 6.这一步要添加的目录与你安装的cplex的目录有关系 F:\program…

idea2023.2.5的控制台动态配置当前环境

一、idea2023.2.5的控制台动态配置当前环境 1.1、idea版本 1.2、配置方式 1.2.1、方式一 1.2.2、方式二 1.3、参考 https://blog.csdn.net/xiaoheihai666/article/details/127757658

举个栗子!Minitab 技巧(8):用 PLS 偏最小二乘分析大豆脂肪影响因素

在上一个 &#x1f330; 中&#xff0c;我们用 Minitab 最小二乘法验证了两个变量&#xff08;单位桶数与运输时间&#xff09;之间是否存在某种关系。那么&#xff0c;在更复杂的场景中&#xff0c;如何验证一组预测变量和一个或多个连续响应变量之间的关系&#xff1f; 假设…

Pandas入门篇(三)-------数据可视化篇2(pandas-plot篇)

目录 概述一、格式1. 生成pandas.plotting对象来生成图表2. 调用plot()函数来生成图表3.支持的图表类型 二、单变量绘图常用图表1. 柱状图&#xff08;bar&#xff09;使用场景代码实现 2. 折线图&#xff08;line&#xff09;&#xff08;默认即为折线图&#xff09;适用场景代…

体育老师工资高吗,奖金有吗

教师的薪资水平与多种因素相关&#xff0c;包括教育经验、工作地点、学校类型以及个人的教学成果等。在讨论体育教师的工资问题时&#xff0c;不能仅仅关注数字&#xff0c;更应了解教育价值和个人发展。 初中体育教师的工资水平受多种因素影响。根据网络统计的数据&#xff0c…

[Spring Cloud] (6)gateway整体加解密

文章目录 简述整体效果后端增加配置nacos增加配置GlobalConfig 添加请求整体解密拦截器DecryptionFilter添加响应整体解密拦截器EncryptionFilter 前端请求拦截器添加整体加密逻辑请求头中添加sessionId 响应拦截器添加整体解密逻辑 简述 本文网关gateway&#xff0c;微服务&a…

阅读欣赏推荐之(七)——纪录片《一根绳子有多长》

《一根绳子有多长》是英国广播公司&#xff08;BBC&#xff09;在2009年出品的纪录片&#xff0c;这部纪录片以一跟绳子作为主角&#xff0c;通过运用现代科技手段&#xff0c;结合历史学、文化学、物理学等多个领域的知识&#xff0c;对绳子进行了全方位的研究。在古代&#x…

诺基亚贝尔探访上海斯歌,共探创新合作新机遇

近日&#xff0c;上海斯歌K2 BPM迎来重要客户考察交流活动。来自诺基亚贝尔的首席数字官刘少勇一行莅临了上海斯歌K2 BPM 的武汉研发中心&#xff0c;并对上海斯歌在BPM业务流程管理领域的研发成果及交付能力给予了高度肯定。 此次活动不仅加深了双方的战略合作&#xff0c;也为…

flask 前后台文件多张图片api;streamlit、gradio多图片页面展示

1、flask 前后台文件多张图片api send_file 传递zip&#xff1a; send_file(zip_data, mimetype‘application/zip’, as_attachmentTrue, download_name‘images.zip’) from flask import Flask, Response, request,send_file from PIL import Image import torch import i…

数据库大作业——基于qt开发的图书管理系统 (一)环境的配置与项目需求的分析

前言 博主最近数据库原理结课要做课程设计了,要求开发基于数据库实现的图书管理系统&#xff0c;博主想了想决定做一个基于Qt的图书管理系统,博主在此之前其实也没有用过多少Qt&#xff0c;仅以此专栏记录博主学习与开发的全过程&#xff0c;大家一起学习&#xff0c;一起进步…

使用固定公网地址远程访问开源服务器运维管理面板1Panel管理界面

文章目录 前言1. Linux 安装1Panel2. 安装cpolar内网穿透3. 配置1Panel公网访问地址4. 公网远程访问1Panel管理界面5. 固定1Panel公网地址 前言 1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。高效管理,通过 Web 端轻松管理 Linux 服务器&#xff0c;包括主机监控、…

npm install 会报错npm audit错误,会提示你有多少个漏洞需要结局等

npm install 会报错 npm audit… 错误&#xff0c;会提示你有多少个漏洞需要结局&#xff0c;对应的包版本不应该低于多少等等问题 当使用npm i 命令的时候会出现以下问题 如果是个新手的话&#xff0c;建议直接关闭npm的audit检查。这样可以保证npm的audit不会影响你的初始…

文献速递:深度学习医学影像心脏疾病检测与诊断--从SPECT/CT衰减图中深度学习冠状动脉钙化评分提高了对重大不良心脏事件的预测

Title 题目 Deep Learning Coronary Artery Calcium Scores from SPECT/CT Attenuation Maps Improve Prediction of Major Adverse Cardiac Events 从SPECT/CT衰减图中深度学习冠状动脉钙化评分提高了对重大不良心脏事件的预测 01 文献速递介绍 低剂量非门控CT衰减校正&am…

ASP.NET网络商店销售管理系统的设计与实现

摘 要 随着软件技术的不断进步和发展&#xff0c;信息化的管理方式越来越广泛的应用于各个领域&#xff0c;对于任何网站系统的管理来说开发一套现代化的成员管理软件是十分必要的。通过这样的软件系统&#xff0c;可以做到成员的规范管理和快速查询&#xff0c;从而减少管理…

TPV-W5 24V 48V 系列——正负双输出和单输出,工业级环境温度,用于PCB安装的国际标准结构

TPV-W5系列提供正负双输出和单输出&#xff0c;工业级环境温度&#xff0c;用于PCB安装的国际标准结构。此系列产品小巧&#xff0c;效率高&#xff0c;低输出纹波及能承受3000V以上的耐压&#xff0c;用于需要正负电压或单输出和高隔离电压的场合。封装有SIP和DIP可选。

JAVA基础之线程池原理与源码简读

线程 线程是调度CPU资源的最小单位&#xff0c;线程模型分为KLT和ULT模型&#xff0c;JVM使用的KLT模型java线程与OS线程保持1:1的映射关系&#xff0c;也就是说每一个java线程对应操作系统一个线程。Java线程有以下几种生命状态&#xff1a; NEW&#xff1a;新建状态RUNNABL…
最新文章