同一文件中多类间Logger的传递与使用问题
Python日志类使用问题解答
原代码
import logging import json class logger(): def __init__(): self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) if not (self.logger.hasHandlers()): #self.logger.handlers.clear() file_handler=logging.FileHandler("qwerty.log") stream_handler=logging.StreamHandler() format_str = {"timestamp":"%(asctime)s"} #Some more stuff format_str = json.dumps(format_str) stream_formatter=logging.Formatter(format_str) file_formatter=logging.Formatter(format_str) file_handler.setFormatter(file_formatter) stream_handler.setFormatter(stream_formatter) self.logger.addHandler(file_handler) self.logger.addHandler(stream_handler) class ABC(): def __init__(): logger.__init__(self) def some_func(): self.logger.info("Hi from ABC") class XYZ(ABC): def __init__(): ABC.__init__(self) logger.__init__(self) #why do I need to do this? def some_func(): self.logger.info("Hi from XYZ") class zxc(): def __init__(): logger.__init__(self) abc = ABC() def some_func(): try: self.logger.info("Hi from ZXC") raise Exception except: self.logger.error("Some issue")
问题1:子类XYZ继承已初始化logger的ABC类,为何仍需再次初始化logger?该实例不可继承吗?
不需要重复初始化,你觉得必须这么做是因为代码存在语法错误:所有__init__方法都未声明第一个参数self,导致调用ABC.__init__(self)时无法正确执行父类初始化逻辑,自然无法继承到self.logger属性。
修正语法错误后,只要ABC的__init__正确调用logger.__init__(self),XYZ继承ABC并调用ABC.__init__(self)后,会自动拥有self.logger,完全不需要单独调用logger.__init__(self)。
问题2:当前在不同类中初始化logger的方式是否正确?同一文件内多类使用logger是否有更优方案?
当前方式存在明显问题:
- 所有
__init__方法缺失self参数,属于语法错误,直接运行会报错; logger类设计冗余,本质是工具逻辑却用实例方法实现,每个业务类都要手动调用初始化,代码重复;- 虽然
logging.getLogger(__name__)是单例(多次调用返回同一个logger实例),但每个类实例都执行初始化逻辑属于重复操作,毫无必要。
更优方案推荐两种:
方案1:全局初始化日志配置
在文件开头一次性完成日志配置,所有类直接使用已配置好的全局logger:
import logging import json # 全局初始化日志,仅执行一次 logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) if not logger.hasHandlers(): file_handler = logging.FileHandler("qwerty.log") stream_handler = logging.StreamHandler() # 直接定义logging规范的格式字符串,不要用json.dumps format_str = "%(asctime)s - %(levelname)s - %(message)s" formatter = logging.Formatter(format_str) file_handler.setFormatter(formatter) stream_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(stream_handler) class ABC(): def some_func(self): logger.info("Hi from ABC") class XYZ(ABC): def some_func(self): logger.info("Hi from XYZ") class zxc(): def some_func(self): try: logger.info("Hi from ZXC") raise Exception except: logger.error("Some issue")
方案2:使用Mixin类
把日志初始化逻辑封装成Mixin类,需要日志功能的业务类直接继承该Mixin,避免重复代码:
import logging import json class LoggerMixin: def __init__(self): self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) if not self.logger.hasHandlers(): file_handler = logging.FileHandler("qwerty.log") stream_handler = logging.StreamHandler() format_str = "%(asctime)s - %(levelname)s - %(message)s" formatter = logging.Formatter(format_str) file_handler.setFormatter(formatter) stream_handler.setFormatter(formatter) self.logger.addHandler(file_handler) self.logger.addHandler(stream_handler) class ABC(LoggerMixin): def __init__(self): super().__init__() def some_func(self): self.logger.info("Hi from ABC") class XYZ(ABC): def __init__(self): super().__init__() # 自动继承LoggerMixin的日志初始化逻辑 def some_func(self): self.logger.info("Hi from XYZ") class zxc(LoggerMixin): def __init__(self): super().__init__() self.abc = ABC() def some_func(self): try: self.logger.info("Hi from ZXC") raise Exception except: self.logger.error("Some issue")
问题3:logger.error的日志可在控制台显示,但无法写入日志文件qwerty.log,无报错信息,请问原因是什么?
核心问题是日志格式字符串处理错误:你把格式字典用json.dumps()转成了JSON字符串,但logging.Formatter需要的是占位符格式的字符串(比如%(asctime)s),而非JSON文本。
举个例子,你生成的format_str是"{\"timestamp\": \"%(asctime)s\"}",这个字符串被传给Formatter后,日志系统无法识别%(asctime)s作为占位符,最终写入文件的内容要么是空的,要么只显示静态JSON结构(不会替换实际时间等动态内容)。
另外还需排查:
- 程序是否拥有
qwerty.log文件的写入权限; - 相对路径是否正确(确认程序运行的工作目录);
- 代码语法错误是否导致FileHandler未被正确创建。
修正方式:去掉json.dumps(),直接定义符合logging规范的格式字符串,示例:
format_str = "%(asctime)s - %(levelname)s - %(message)s" formatter = logging.Formatter(format_str)
内容的提问来源于stack exchange,提问作者qwerty
相关产品推荐
相关产品推荐

