Logger
类详解:全局日志管理器的设计与实现
类定义与功能概述
Logger
类是一个基于 Qt 信号槽机制的全局日志管理组件,主要功能是统一收集各模块的日志消息并通过信号发送,实现日志的集中管理和显示。
class Logger(QObject):
"""全局日志管理器,通过信号传递日志消息"""
log_message = pyqtSignal(str) # 定义日志消息信号,携带字符串参数
def log(self, message):
"""发送日志消息到信号"""
self.log_message.emit(message)
核心组成部分分析
-
信号定义:
log_message = pyqtSignal(str)
- 这是一个自定义的 Qt 信号,用于传递日志消息字符串
- 信号是 Qt 框架中对象间通信的核心机制,支持跨线程安全通信
- 当信号被触发(
emit
)时,所有连接到该信号的槽函数会被调用
-
日志发送方法:
def log(self, message): self.log_message.emit(message)
log
方法是外部调用的接口,接收日志消息- 通过
emit
触发信号,将日志消息传递给所有连接的槽函数 - 该设计实现了"发送日志"与"显示日志"的解耦,符合开闭原则
在项目中的应用场景
-
主窗口中的初始化:
class MainWindow(QMainWindow): def __init__(self): # 初始化全局日志管理器 self.logger = Logger() # 连接信号到界面显示槽函数 self.logger.log_message.connect(self.log_to_ui)
- 在主窗口中创建
Logger
实例 - 将信号连接到主窗口的
log_to_ui
方法(用于在界面显示日志)
- 在主窗口中创建
-
数据库模块中的使用:
class DatabaseManager: def __init__(self, server, database, username, password, logger=None): self.logger = logger # 接收日志管理器实例 def log_message(self, message): if self.logger: self.logger.log(message) # 通过日志管理器发送日志
- 数据库操作模块通过构造函数接收
Logger
实例 - 所有数据库相关日志通过
logger.log(message)
发送
- 数据库操作模块通过构造函数接收
-
界面组件中的集成:
class MaterialBindingWidget(QWidget): def __init__(self, db_manager, logger=None, parent=None, table_name="T_IN", title="常温上料绑定"): self.logger = logger # 接收日志管理器实例 def log_message(self, message): if self.logger: self.logger.log(message) # 通过日志管理器发送日志
- 界面组件同样通过构造函数接收
Logger
实例 - 按钮点击、数据提交等操作的日志通过统一接口发送
- 界面组件同样通过构造函数接收
信号槽机制的优势
-
解耦设计:
- 日志发送方(如数据库模块)与接收方(主窗口日志显示)无需互相引用
- 模块间通过信号槽通信,符合"高内聚、低耦合"的设计原则
-
跨线程安全:
- Qt 的信号槽机制原生支持跨线程通信
- 即使日志发送和显示在不同线程,也能保证线程安全
-
灵活扩展:
- 可以轻松添加新的日志接收方(如文件日志、网络日志)
- 只需将新组件的槽函数连接到
log_message
信号即可
实际工作流程示例
-
日志产生:
self.logger.log("[操作] 点击提交按钮,条码: 123456, 批次: Batch001")
- 某组件调用
logger.log
方法发送日志消息
- 某组件调用
-
信号触发:
def log(self, message): self.log_message.emit(message) # 触发信号,携带日志消息
Logger
类将日志消息通过信号发出
-
信号接收与处理:
class MainWindow(QMainWindow): def __init__(self): self.logger.log_message.connect(self.log_to_ui) # 连接信号到槽 def log_to_ui(self, message): self.log_text.append(message) # 在界面日志区域显示消息
- 主窗口的
log_to_ui
方法作为槽函数,接收信号并更新界面
- 主窗口的
与其他日志方案的对比
方案 | 优势 | 不足 |
---|---|---|
Logger信号槽方案 | 1. 完全符合Qt框架设计哲学 2. 跨线程安全 3. 低耦合易扩展 | 需要理解Qt信号槽机制 |
全局变量方案 | 实现简单 | 1. 耦合度高 2. 跨线程不安全 |
继承重写方案 | 代码直观 | 1. 子类化复杂 2. 扩展性差 |
扩展建议
-
日志级别支持:
class Logger(QObject): log_debug = pyqtSignal(str) log_info = pyqtSignal(str) log_warning = pyqtSignal(str) log_error = pyqtSignal(str) def debug(self, message): self.log_debug.emit(f"[DEBUG] {message}") def info(self, message): self.log_info.emit(f"[INFO] {message}") # 其他级别类似...
-
日志持久化:
class FileLogger(QObject): def __init__(self, log_file): self.log_file = log_file @pyqtSlot(str) def save_to_file(self, message): with open(self.log_file, 'a', encoding='utf-8') as f: f.write(f"{QDateTime.currentDateTime().toString()} - {message}\n")
- 创建文件日志组件,将其槽函数连接到
Logger
信号
- 创建文件日志组件,将其槽函数连接到
-
日志过滤:
class FilterLogger(QObject): def __init__(self, filter_keywords): self.filter_keywords = filter_keywords @pyqtSlot(str) def filter_and_log(self, message): if any(keyword in message for keyword in self.filter_keywords): # 处理过滤后的日志
总结
Logger
类通过 Qt 的信号槽机制实现了全局日志的统一管理,具有低耦合、跨线程安全、易扩展的特点。这种设计使得系统各模块可以独立产生日志,而日志的显示和处理逻辑集中在主窗口,便于维护和功能扩展,是 Qt 应用中推荐的日志管理方案。