设置高级Python日志记录

5 投票
1 回答
2255 浏览
提问于 2025-04-17 12:40

我想在我的模块中使用日志记录,但我不太确定如何设计以下需求:

  • 需要有正常的日志级别(信息、错误、警告、调试),还需要一些更详细的调试级别
  • 日志消息可以有不同的类型;有些是给开发者看的,有些是给用户看的;这些类型需要输出到不同的地方
  • 错误信息应该输出到 stderr(标准错误输出)
  • 我还需要记录是哪个模块、哪个函数、哪一行代码写了调试消息,这样我就可以在配置中激活或停用特定的调试消息
  • 我需要跟踪是否发生了错误,以便在程序结束时执行 sys.exit()
  • 在设置日志记录器之前,所有消息都应该输出到 stdout(标准输出)

我看过日志记录的文档,但不太确定如何以最简洁的方式使用日志模块来满足上述需求(比如如何使用 Logger、Handler、Filter 等概念)。你能给我一些设置的建议吗?(例如,写一个模块,里面有两个日志记录器 'user' 和 'developer';从 Logger 继承;使用 getLogger(__name__);像这样保持错误标志等等。)

1 个回答

10

1) 增加更详细的调试级别

你考虑清楚了吗?

看看文档是怎么说的:

定义你自己的日志级别是可以的,但不应该是必要的,因为现有的级别是基于实际经验选择的。不过,如果你坚信需要自定义级别,在这样做时要非常小心,而且如果你在开发一个库,定义自定义级别可能是个很糟糕的主意。这是因为如果多个库的作者都定义了自己的自定义级别,那么一起使用这些库时,开发者可能会很难控制和理解日志输出,因为同一个数字在不同的库中可能代表不同的意思。

另外,看看何时使用日志,里面有两个很好的表格解释了什么时候使用什么。

总之,如果你觉得需要那些额外的日志级别,可以看看:logging.addLevelName()

2) 一些日志信息给开发者,一些给用户

使用不同的日志记录器家族和不同的处理器。在每个家族的基础上,将Logger.propagate设置为False

3) 错误信息应该输出到stderr

这已经是默认设置了,使用StreamHandler

class logging.StreamHandler(stream=None)

返回一个新的StreamHandler类的实例。如果指定了流,实例将使用它进行日志输出;否则,将使用sys.stderr

4) 记录日志信息的来源

使用不同名称的日志记录器,在你的格式化器中使用包含%(name)s的格式字符串。

5) 所有信息在设置日志记录器之前都应该输出到stdout

设置你的日志系统应该是最先做的事情之一,所以我不太明白这是什么意思。如果你需要发送信息到stdout,使用print就可以了,这在何时使用日志中已经解释过了。

最后的建议:仔细阅读日志记录食谱,因为它很好地涵盖了你需要的内容。


来自评论: 我该如何设计以便输出到不同的来源并过滤我的模块?

我一开始不会进行过滤,过滤器很难维护,如果都放在一个地方,那地方会承载太多信息。每个模块应该获取并设置自己的Logger(带有自己的处理器或过滤器),可以使用或不使用其父级设置。

非常简单的例子:

# at the very beginning
root = logging.getLogger()
fallback_handler = logging.StreamHandler(stream=sys.stdout)
root.addHandler(fallback_handler)

# first.py
first_logger = logging.getLogger('first')
first_logger.parent = False
# ... set 'first' logger as you wish
class Foo:
    def __init__(self):
        self.logger = logging.getLogger('first.Foo')
    def baz(self):
        self.logger.info("I'm in baz")

# second.py
second_logger = logging.getLogger('first.second') # to use the same settings

# third.py
abstract_logger = logging.getLogger('abs')
abstract_logger.parent = False
# ... set 'abs' logger
third_logger = logging.getLogger('abs.third')
# ... set 'abs.third' particular settings

# fourth.py
fourth_logger = logging.getLogger('abs.fourth')
# [...]

撰写回答