文章目录(Table of Contents)
简介
在 Python 中,日志是一种重要的工具,用于记录程序运行时的信息、警告和错误。Python 内置了logging
模块作为标准日志库,但其使用起来相对繁琐。而loguru
是一个简单易用的第三方日志库,可以提供美观、简洁的日志输出,并且具有更方便的配置和使用方式。
相比于logging
库,为什么我们应该选择使用loguru
呢?首先,loguru
提供了一种更简单的日志记录方式,通过直接调用logger
对象的方法即可完成日志记录,无需额外配置。其次,loguru
的日志输出格式默认较为美观,可以直接显示时间、日志级别和消息内容,方便阅读。此外,loguru
还支持灵活的日志处理器配置,可以轻松地将日志记录到文件、控制台或其他地方,满足不同场景的需求。
在接下来的内容中,我们将详细介绍loguru
的使用方法,并演示一些常用功能和技巧。
参考资料
- Python 的 logging 模块的使用,前一篇文章对 logging 模块的介绍;
- Python logging made (stupidly) simple,loguru 的官方 Github 仓库;
- Python - 日志管理模块: Loguru的使用,CSDN 上一篇关于 loguru 的介绍;
Loguru 的使用
直接使用
首先让我们看一下最简单的loguru
使用示例。下面的代码示例展示了如何直接使用loguru
进行日志记录:
- from loguru import logger
- logger.debug("That's it, beautiful and simple logging!")
以上代码中,我们导入了logger
对象,并调用其debug
方法记录一条日志。loguru
会自动将日志输出到控制台,并显示时间戳、日志级别和消息内容。这种直接使用的方式非常简单,适用于快速的日志记录需求。下面是输出的结果示例:
需要注意,由于 loguru
只有一个对象,因此 loguru 可以在多个 module 中使用,而不会出现冲突。
添加 handler
除了直接使用loguru
进行日志记录外,我们还可以通过添加处理器来自定义日志的输出方式和格式。下面的代码示例展示了如何使用loguru
的add
函数添加处理器(handler):
- import sys
- from loguru import logger
- def stringFilter(record) -> bool:
- # 只记录出现 RL 的 log
- if 'RL' in record['message']:
- return True
- return False
- # 添加或删除 handler
- logger.remove() # 删除原有的 handler
- logger.add(sys.stderr, format="Without Filter: <green>{time}</green> | {level} | {message}", level="INFO", colorize=True) # 不会显示 debug 的日志
- logger.add(sys.stderr, format="With Filter: {file} | {line} | {level} | <level>{message}</level>", filter=stringFilter, level="DEBUG")
- # 添加日志
- logger.info("That's it, beautiful and simple logging!")
- logger.info("RL: Info, Test Filter.")
- logger.debug("RL: Debug-1, Test Filter.")
- logger.debug("Debug-2, Test Filter.")
在上述代码中:
- 我们首先使用
logger.remove()
函数删除了原有的处理器; - 然后使用
logger.add()
函数添加了两个处理器。- 第一个处理器的日志级别为 INFO,使用了自定义的格式,并启用了颜色显示。
- 第二个处理器的日志级别为 DEBUG,并使用了自定义的过滤器(只显示有 RL 的日志)。
通过添加处理器,我们可以根据需求自由地配置日志的输出方式和格式。下面是最终的输出。可以看到第一个处理器不会显示 DEBUG,第二个只显示有 RL 的日志:
下面是不同的等级,例如我们设置为 INFO
,那么所有的 DEBUG
的信息就会看不到:
记录到文件中
除了将日志输出到控制台外,loguru
还支持将日志记录到文件中。下面的代码示例展示了如何使用loguru
将日志记录到文件中(只需要将 add
中修改为文件名即可):
- from loguru import logger
- def stringFilter(record) -> bool:
- # 只记录出现 RL 的 log
- if 'RL' in record['message']:
- return True
- return False
- # 添加或删除 handler
- logger.remove() # 删除原有的 handler
- logger.add('./log-{time}.log', format="{time} {level} {message}", filter=stringFilter, level="DEBUG", rotation="1 MB")
- # 添加日志
- logger.info("That's it, beautiful and simple logging!")
- logger.info("RL: Info, Test Filter.")
- logger.debug("RL: Debug-1, Test Filter.")
- logger.debug("Debug-2, Test Filter.")
在上述代码中,我们使用logger.add()
函数将日志记录到文件中。通过指定文件路径和格式,我们可以将日志输出到指定的文件中,并根据需要进行日志轮换、日志保留等操作。在示例中,我们使用了一个自定义的过滤器,只记录包含"RL"的日志消息。
除此之外,还有一系列的轮换方式:
- 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
异常捕捉
loguru
还提供了异常捕捉功能,可以方便地记录异常信息。下面的代码示例展示了如何使用loguru
捕捉并记录异常:
- from loguru import logger
- logger.add('./log-{time}.log', rotation="1 MB")
- @logger.catch
- def my_function(x, y, z):
- try:
- a = 1 / (x + y + z)
- return a
- except ZeroDivisionError:
- raise f'除数不为 0.'
- a = my_function(0,0,0)
- print(a)
在上述代码中,我们使用logger.catch
装饰器捕捉了my_function
函数中的异常,并将异常信息记录到日志中。通过使用该装饰器,我们可以方便地捕捉和记录函数中的异常,避免程序崩溃,并可以在日志中查看详细的异常信息。如下所示,可以看到非常详细的堆栈调用:
除了上面的方式外,loguru
还支持使用 backtrace 来进行记录。我们使用logger.add()
函数添加了一个处理器,并通过设置backtrace=True
和diagnose=True
参数来启用异常的调用栈信息记录。当程序发生异常时,loguru
会将异常的调用栈信息记录到日志中,方便我们进行故障排查和问题定位。
- logger.add("out.log", backtrace=True, diagnose=True) # Caution, may leak sensitive data in prod
或者是可以使用 logger.exception
的方式来异常的捕获和记录:
- from loguru import logger
- def func(a, b):
- return a / b
- def nested(c):
- try:
- func(5, c)
- except ZeroDivisionError:
- logger.exception("What?!")
- nested(0)
bind,绑定参数
loguru
的bind
方法可以用于绑定额外的参数到日志记录中,方便我们在日志中添加自定义的上下文信息。下面的代码示例展示了如何使用bind
方法绑定参数:
- import sys
- from loguru import logger
- logger.add(sys.stderr, format="{extra} - {extra[ip]} - {message}")
- class Server:
- def __init__(self, ip, user):
- self.ip = ip
- self.user = user
- self.logger = logger.bind(ip=ip, user=user)
- def call(self, message):
- self.logger.info(message)
- instance_1 = Server("192.168.0.200", "user1")
- instance_2 = Server("127.0.0.1", "user2")
- instance_1.call("First instance")
- instance_2.call("Second instance")
在上述代码中,我们定义了一个Server
类,并在其中使用logger.bind()
方法绑定了ip
和user
两个参数。在call
方法中,我们使用了self.logger.info()
方法记录日志,并在日志格式中添加了额外的上下文信息。通过绑定参数,我们可以方便地在日志中添加自定义的上下文信息,提供更详细的日志内容。
启用和禁用日志
loguru
还提供了启用和禁用日志的功能,可以根据需要控制日志的输出。下面的代码示例展示了如何使用loguru
启用和禁用日志:
- import sys
- from loguru import logger
- # For scripts
- config = {
- "handlers": [
- {"sink": sys.stdout, "format": "{time} - {message}"},
- {"sink": "file.log", "serialize": True},
- ],
- "extra": {"user": "someone"}
- }
- logger.configure(**config)
- if __name__ == '__main__':
- # For libraries, should be your library's `__name__`
- logger.disable("__main__")
- logger.info("No matter added sinks, this message is not displayed")
- # In your application, enable the logger in the library
- logger.enable("__main__")
- logger.info("This message however is propagated to the sinks")
在上述代码中,我们首先使用logger.configure()
函数配置了日志处理器,并指定了日志输出到控制台和文件中。在if name == 'main'
条件下,我们使用logger.disable()
函数禁用了指定名称的日志输出,使得该名称下的日志不会被记录。然后,我们使用logger.enable()
函数启用了指定名称的日志输出,使得该名称下的日志可以正常记录。
通过启用和禁用日志的功能,我们可以根据需要灵活地控制日志的输出,避免不必要的日志记录。
- 微信公众号
- 关注微信公众号
- QQ群
- 我们的QQ群号
评论