Python 3中基类日志Handler仅添加一次的Pythonic实现及日志拓展问题
Python日志Handler单次执行的Pythonic实现及__main__日志记录问题
我正在尝试记录当前运行的完整类名和方法。在下方的示例代码中,我通过Base类的类属性log_handler_added来跟踪日志Handler是否已添加:如果没有这个控制逻辑,基类每被继承一次就会输出一条重复日志,错误输出示例如下:
1688489421.224986 DEBUG Base.TestClassA.testmethod1 |debug message from test class A| 1688489421.225088 INFO Base.TestClassB.testmethod2 |info message from test class B| 1688489421.225088 INFO Base.TestClassB.testmethod2 |info message from test class B| 1688489421.225162 ERROR Base.TestClassC.another_method |error message from test class C| 1688489421.225162 ERROR Base.TestClassC.another_method |error message from test class C| 1688489421.225162 ERROR Base.TestClassC.another_method |error message from test class C|
我在__init__方法末尾添加判断逻辑,仅调用一次self.__logger.addHandler(console_handler)后,得到了正确的输出:
1688490430.369992 DEBUG Base.TestClassA.testmethod1 |debug message from test class A| 1688490430.370093 INFO Base.TestClassB.testmethod2 |info message from test class B| 1688490430.370155 ERROR Base.TestClassC.another_method |error message from test class C|
但我觉得这种实现方式不够健壮,作为新手缺乏相关经验判断,因此有两个疑问:
- 调用
self.__logger.addHandler(console_handler)仅执行一次的正确Pythonic方式是什么? - 能否利用当前的元类+继承机制在
__main__中记录日志?
示例代码如下:
#!/usr/bin/env python3 import logging class MetaBase(type): def __init__(cls, *args): super().__init__(*args) # 显式命名改写 logger_attribute_name = "_" + cls.__name__ + "__logger" # 考虑继承关系生成日志器名称 logger_name = ".".join([c.__name__ for c in cls.mro()[-2::-1]]) setattr(cls, logger_attribute_name, logging.getLogger(logger_name)) class Base(metaclass=MetaBase): log_handler_added = False def __init__(self): log_formatter = logging.Formatter( "{created:<f} {levelname:>5s} {name}.{funcName:>8s} |{message}|", style="{", ) loglevel = "DEBUG" # 将日志级别字符串转为对应的数值 numeric_level = getattr(logging, loglevel.upper(), None) if not isinstance(numeric_level, int): raise ValueError("Invalid log level: %s" % loglevel) # 仅输出到 stdout/stderr console_handler = logging.StreamHandler() console_handler.setFormatter(log_formatter) self.__logger.setLevel(numeric_level) # 使用类属性控制仅添加一次Handler,避免基类每次被继承都重复添加 if not Base.log_handler_added: self.__logger.addHandler(console_handler) Base.log_handler_added = True class TestClassA(Base): def testmethod1(self): self.__logger.debug("debug message from test class A") class TestClassB(Base): def testmethod2(self): self.__logger.info("info message from test class B") class TestClassC(Base): def another_method(self): self.__logger.error("error message from test class C") a = TestClassA() a.testmethod1() b = TestClassB() b.testmethod2() p = TestClassC() p.another_method()
内容的提问来源于stack exchange,提问作者acjca2
相关产品推荐
相关产品推荐

