酷炫的python日志库-loguru


Loguru是一个python的日志库,比logging更简单,好用,功能丰富。

GitHub - Delgan/loguru: Python logging made (stupidly) simple

官方文档:Overview — loguru documentation

安装

pip install loguru

特征
开箱即用,补样板
没有处理程序,没有清理程序,没有过滤器:一个函数可以统治所有这些
通过旋转/保留/压缩更轻松地记录文件
使用大字符串样式的现代字符串格式
在线程或主线程中捕获异常
漂亮的颜色记录
异步、线程安全、多进程安全
完整描述性异常
根据需要形成日志记录
昂贵费用的评估
可定制的级别
更好的日期时间处理
适用于脚本和库
与标准日志记录完全兼容
通过环境变量进行个性化默认设置
方便的解析器
观赏的通知程序
比内置日志记录快 10 倍

开箱即用

Loguru 的主要概念只有一个 。logger

为了方便入门,它默认配置输出到控制台 stderr,但是是可以配置的

from loguru import logger

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

在控制台按照格式输出
在这里插入图片描述

配置日志记录器

方法add可以添加handle,设置log format,过滤消息,设置level

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

这行代码是使用 loguru 库来配置一个日志记录器(logger)。loguru 是一个 Python 日志库,它旨在提供简单、快速和灵活的日志记录功能。

  1. logger.add(...): 这是 loguru 的 API,用于添加一个日志处理器(handler)。日志处理器决定了日志消息应该发送到哪里以及如何格式化。
  2. sys.stderr: 这是 Python 的标准错误输出流。这行代码将日志消息发送到 sys.stderr,这意味着它们将打印到控制台,并且通常会被认为是错误或警告消息。
  3. format="{time} {level} {message}": 这是日志消息的格式。{time}{level}{message} 是占位符,它们分别会被替换为当前的时间、日志级别和日志消息。这样,每条日志消息都会以这种格式输出。
  4. filter="my_module": 这是一个过滤器。只有当日志消息来自名为 “my_module” 的模块时,这条处理器规则才会应用。这意味着,只有 “my_module” 产生的日志消息才会被发送到 sys.stderr 并以指定的格式显示。
  5. level="INFO": 这是日志级别。只有级别为 “INFO” 或更高的日志消息才会被这条处理器规则捕获。loguru 支持的日志级别有:DEBUG, INFO, SUCCESS, WARNING, ERROR, CRITICAL 和 FATAL。

总之,这行代码的意思是:为 logger 添加一个处理器,该处理器将 “my_module” 产生的级别为 “INFO” 或更高的日志消息发送到 sys.stderr,并以指定的格式显示这些消息。
此函数评估注册负责管理与记录字典上下文相关的日志消息的接收器。接收器可以采用多种形式:简单函数、字符串路径、类文件对象、协程函数或内置处理程序。

移除日志处理器

logger.remove()

loguru 库中,logger.remove() 方法用于移除一个先前添加的日志处理器。当你不再需要某个特定的日志处理器时,可以使用这个方法将其移除。

通常,你会在添加处理器时为其分配一个唯一的标识符(ID),然后在需要移除它时使用这个ID。如果你没有提供ID,loguru 会移除所有匹配的处理器。

例如,假设你之前这样添加了一个处理器:

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

你可以使用相同的 handler_id 来移除这个处理器:

logger.remove(handler_id)

如果你没有保留处理器的ID,但你知道你想要移除的处理器的其他属性(比如它的目标、格式、过滤器或级别),你可以使用这些属性来移除处理器。但是,请注意,这可能会移除多个匹配的处理器。

例如,要移除所有发送到 sys.stderr 的处理器,你可以这样做:

logger.remove(sys.stderr)

或者,要移除所有使用特定格式的处理器:

logger.remove(format="{time} {level} {message}")

请注意,移除处理器不会影响已经记录但尚未发送到处理器的日志消息。它只是改变了未来日志消息的处理方式。

还要注意的是,logger.remove() 方法并不会引发错误,即使没有找到匹配的处理器。如果找不到匹配的处理器,该方法将默默地什么都不做。

日志输出到文件

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

日志轮转/删除/压缩

如果您需要旋转记录器,如果您想删除较旧的日志,或者如果您希望在关闭时压缩文件,它也可以轻松配置。

logger.add(“file_1.log”, rotation=“500 MB”) # Automatically rotate too big file

loguru 库中,logger.add() 方法用于向日志记录器添加一个新的处理器,这个处理器将日志消息写入到指定的文件。在你给出的代码示例中:

logger.add("file_1.log", rotation="500 MB")

这行代码的意思是向 logger 添加一个处理器,该处理器会将日志消息写入到名为 “file_1.log” 的文件中。rotation="500 MB" 表示当日志文件的大小达到 500 MB 时,loguru 会自动进行日志文件的轮转(rotation)。

轮转是日志管理中的一个常见概念,它指的是当日志文件达到一定的大小或满足其他条件时,自动关闭当前日志文件并开始写入一个新的日志文件。这有助于防止日志文件变得过大,使得管理和查看日志变得更加容易。

loguru 中,轮转可以通过多种方式触发,例如:

  • 按文件大小:如上述示例所示,当文件达到 500 MB 时进行轮转。
  • 按时间:例如,你可以设置每天、每周或每月进行轮转。
  • 按日志条数:当达到一定的日志条数时进行轮转。

当你使用 rotation 参数时,loguru 会自动处理轮转逻辑,包括创建新的日志文件、给新文件命名(通常是在原文件名的基础上加上一个时间戳或序号),以及(如果需要的话)压缩旧的日志文件以节省空间。

这是一个完整的示例,展示了如何使用 loguru 向文件添加日志处理器,并设置按文件大小进行轮转:

from loguru import logger

# 创建一个logger实例
logger = logger()

# 添加一个处理器,将日志写入到file_1.log,并在文件大小达到500 MB时进行轮转
logger.add("file_1.log", rotation="500 MB")

# 记录一些日志
logger.info("This is an info message.")
logger.error("This is an error message.")

在这个示例中,日志消息将被写入到 “file_1.log” 文件中。当该文件的大小达到 500 MB 时,loguru 会自动开始写入一个新的日志文件,比如 “file_1.log.1”,并继续记录日志,直到下一个轮转点。
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

字符串格式化

Loguru 更喜欢更优雅和更强大的{}格式%,日志记录功能实际上等同于str.format()。

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

在线程或主线程中捕获异常

您是否曾遇到过您的程序意外崩溃而在日志文件中看不到任何内容?您是否注意到线程中发生的异常没有被记录?这可以使用装饰器/上下文管理器来解决,它确保任何错误都传播到正确的地方。catch()logger

@logger.catch
def my_function(x, y, z):
    # An error? It's caught anyway!
    return 1 / (x + y + z)

漂亮的颜色记录

如果您的兼容,Loguru 会自动为您的日志添加颜色。您可以通过使用接收器格式的标记来定义您喜欢的样式。

logger.add(sys.stdout, colorize=True, format=“{time} {message}”)

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

默认情况下,添加到的所有接收器都是线程安全的。它们不是多进程安全的,但您可以通过消息来确保日志的限制。如果您想要异步日志记录,也可以使用相同的参数。loggerenqueue

logger.add(“somefile.log”, enqueue=True)
首先接收器的协程函数也受支持,并且应该使用等待。complete()

完整描述异常

记录代码中的异常对于跟踪错误非常重要,但如果您不知道失败的原因,那么它就没用处。Loguru 通过允许显示整个堆栈(跟踪包括标记值)来帮助您识别问题(感谢您!) 。better_exceptions

代码:

logger.add("out.log", backtrace=True, diagnose=True)  # Caution, may leak sensitive data in prod

def func(a, b):
    return a / b

def nested(c):
    try:
        func(5, c)
    except ZeroDivisionError:
        logger.exception("What?!")

nested(0)

需要注意,要想输出栈,必须用try except去捕捉。
在这里插入图片描述

根据需要形成日志记录
想要对您的日志进行序列化以便解析或传送它们吗?使用该serialize参数,每条日志消息在发送到配置的接收器之前都将转换为 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.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”)
可以使用以下命令临时修改上下文本地状态:contextualize()

with logger.contextualize(task=task_id):
do_something()
logger.info(“End of task”)
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()))

配置全局选项logger.opt()

loguru 库中,Logger.opt() 方法用于配置日志记录器的全局选项。这个方法允许你改变日志记录器的默认行为,例如设置默认的日志级别、更改默认的格式,或者配置其他全局参数。

Logger.opt() 方法接受多个关键字参数,每个参数都对应一个可配置的全局选项。以下是一些常用的选项和它们的含义:

  • level: 设置默认的日志级别。例如,level="WARNING" 会使得只有警告级别及以上的日志消息才会被记录。
  • format: 设置默认的日志格式。你可以使用格式字符串来定义日志消息的外观。
  • colors: 控制日志消息是否应该使用颜色。可以是 True(总是使用颜色)、False(从不使用颜色)或 {"level": True, "message": False}(只对特定部分使用颜色)。
  • serialize: 控制是否应该序列化日志消息。在某些情况下,例如当日志消息包含不能直接写入文件的对象时,这可能会很有用。
  • backtrace: 控制是否应该自动添加错误回溯(backtrace)到异常日志消息中。
  • exception: 控制是否应该自动记录异常和它们的回溯。
  • enqueue: 控制日志消息是否应该被排队处理,而不是立即写入处理器。这对于在多线程环境中使用 loguru 很有用。

下面是一个使用 Logger.opt() 方法配置日志记录器的示例:

from loguru import logger

# 配置日志记录器的全局选项
logger.opt(
    level="DEBUG",          # 设置默认日志级别为DEBUG
    format="{time} {level} {message}",  # 设置默认的日志格式
    colors=True,           # 启用颜色输出
    backtrace=True,        # 对错误消息添加回溯
    enqueue=True,          # 启用队列处理
)

# 记录一些日志
logger.debug("This is a debug message.")
logger.info("This is an info message.")
logger.error("This is an error message.")

在这个示例中,Logger.opt() 方法被用来配置日志记录器的全局选项。我们设置了默认的日志级别为 DEBUG,定义了日志消息的格式,启用了颜色输出,以及为错误消息添加了回溯。这意味着所有记录的日志消息都将使用我们指定的格式,并且错误消息将包含有助于调试的回溯信息。

请注意,Logger.opt() 方法必须在添加任何处理器之前调用,以确保新配置能够应用到所有后续的处理器。如果在添加处理器之后更改了全局选项,那么已经存在的处理器将不会受到影响,除非你重新添加它们或更改它们的配置。

logger.opt和logger.add的区别

loguru 库中的 Logger.opt()Logger.add() 方法在日志配置中扮演着不同的角色。

Logger.opt() 方法主要用于配置日志记录器的全局选项。这意味着你可以使用它来设置默认的日志级别、格式、颜色输出、是否添加错误回溯等。这些设置将应用于所有通过该记录器发出的日志消息,除非在特定的处理器或日志消息中明确覆盖了这些设置。Logger.opt() 必须在添加任何处理器之前调用,以确保新配置能够应用到所有后续的处理器。

例如:

logger.opt(level="DEBUG", format="{time} {level} {message}", colors=True)

Logger.add() 方法则用于向日志记录器添加一个新的处理器。处理器决定了日志消息应该发送到哪里以及如何格式化。你可以通过 Logger.add() 方法将日志消息输出到控制台、文件、数据库或其他目标。你还可以为每个处理器指定不同的格式、过滤器、级别和轮转策略。

例如,将日志消息输出到文件:

logger.add("file.log", rotation="10 MB")

或者将日志消息输出到控制台:

logger.add(sys.stderr, level="ERROR")

总结一下,Logger.opt() 是用来配置日志记录器的全局默认选项的,而 Logger.add() 是用来添加具体的日志处理器,定义日志消息的输出目标和格式的。你可以在全局配置的基础上,通过添加多个处理器来实现复杂的日志管理需求。

lazy message

有时您想在生产过程中记录信息而不是损失,您可以使用详细的方法来实现这一点。opt()

logger.opt(lazy=True).debug(“If sink level <= DEBUG: {x}”, x=lambda: expensive_function(2**64))
loguru 中,logger.opt(lazy=True)logger.debug() 的结合使用提供了一种非常有趣且有用的特性,即延迟(lazy)日志消息的计算。这通常用于提高程序的性能,尤其是在你不确定日志消息是否会被实际记录的情况下。

让我们详细解释这段代码:

logger.opt(lazy=True).debug("If sink level <= DEBUG: {x}", x=lambda: expensive_function(2**64))
  1. logger.opt(lazy=True): 这里,lazy=True 配置选项被设置,它告诉 loguru 在实际需要将日志消息发送到其处理器(sink)之前,不要评估日志消息中的任何参数或表达式。这特别有用,因为某些日志消息可能涉及昂贵的操作,例如调用复杂的函数或执行计算密集型的任务。通过使用 lazy=True,你可以避免在不必要的情况下执行这些操作。

  2. logger.debug(...): 这是一个 debug 级别的日志消息。根据 logger 的配置,如果任何处理器的级别设置为 DEBUG 或更低,那么这条消息就会被记录。

  3. "If sink level <= DEBUG: {x}": 这是日志消息的格式字符串。{x} 是一个占位符,它将被后面传递的 x 参数的值替换。

  4. x=lambda: expensive_function(2**64): 这里,x 参数的值是一个 lambda 函数,该函数在被调用时会执行 expensive_function(2**64)。由于 lazy=True 被设置,这个 lambda 函数不会被立即执行。相反,它会在日志消息实际被发送到处理器时被调用。

当这条日志语句被执行时,expensive_function(2**64) 实际上不会被调用,除非当前的日志级别设置为 DEBUG 或更低,并且至少有一个处理器的级别也设置为 DEBUG 或更低。如果日志级别高于 DEBUG,则由于 lazy=True 的设置,昂贵的函数调用将被避免,从而节省了计算资源。

这种延迟评估的特性使得 loguru 在处理可能涉及大量计算或资源的日志消息时非常高效。你可以安全地记录可能非常昂贵的操作,而不用担心在不必要的情况下浪费资源。

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 colors”)
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”)

可定制的级别

Loguru 附带了添加和的所有标准日志记录级别。

new_level = logger.level(“SNAKY”, no=38, color=“”, icon=“🐍”)

logger.log(“SNAKY”, “Here we go!”)

更好的日期时间处理

标准日志记录因datefmt或msecs、%(asctime)s和%(created)s、没有时区信息的简单日期时间、不解读的格式等参数而构建聚合。Loguru修复了它:

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

在日志中输出的格式为 2024-02-24 at 15:41:10 | DEBUG | That’s it, beautiful and simple logging!

在这里插入图片描述

适用于脚本和库

在脚本中使用记录器很简单,您可以从一开始就使用它。要从库内部使用 Loguru,请记住永远不要调用相反的使用,以便日志记录函数设为无操作。如果开发人员希望查看您的库房日志,他们可以再次查看。configure()add()disable()enable()

config = {
“handlers”: [
{“sink”: sys.stdout, “format”: “{time} - {message}”},
{“sink”: “file.log”, “serialize”: True},
],
“extra”: {“user”: “someone”}
}
logger.configure(**config)

For libraries, should be your library’s __name__
logger.disable(“my_library”)
logger.info(“No matter added sinks, this message is not displayed”)

In your application, enable the logger in the library
logger.enable(“my_library”)
logger.info(“This message however is propagated to the sinks”)
为了更加方便,您还可以使用该库直接从配置文件进行设置。loguru-configlogger

与标准日志记录完全兼容

希望使用内置日志记录Handler作为 Loguru 接收器?

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

需要将Loguru消息传播到标准日志记录吗?

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

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

想要拦截发送至Loguru接收器的标准日志消息吗?

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 = sys._getframe(6), 6
    while frame and 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} | {message}”

Windows

setx LOGURU_DEBUG_COLOR “”

方便的解析器

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

pattern = r"(?P

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 可以轻松地与强大的库(必须单独安装)结合使用,方便在程序意外失败时接收电子邮件或发送许多其他类型的通知。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”)

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值