feat: implement unified logging system for GUI components

Add centralized logging mechanism that simultaneously outputs to console
and GUI log components, improving code maintainability and consistency.

Changes:
- Add gui/log_config.py for centralized logging configuration
- Add gui/widgets/log_handler.py as bridge between logging and LogText
- Integrate unified logging into DataExtractionTab and MaterialValidationTab
- Initialize logging system in MainWindow on startup
- Improve error messages in material_status_validator for empty results
- Add documentation for logging mechanism and refactoring

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-02-24 20:31:59 +08:00
parent 3c45ef58d1
commit 24053c6a3b
9 changed files with 821 additions and 24 deletions

View File

@@ -9,12 +9,14 @@
import os
import sys
import threading
import logging
import queue
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from pathlib import Path
from gui.widgets import FileSelector, LogText, ProductionIdInput
from gui.widgets import FileSelector, LogText, ProductionIdInput, GuiTextHandler
from gui.config_manager import ConfigManager
from gui.log_config import setup_gui_logging, get_logger
from gui.progress import ProgressInfo, ProgressCalculator
from gui.utils import RealtimeOutput
@@ -32,6 +34,10 @@ class DataExtractionTab(ttk.Frame):
self.progress_calculator = ProgressCalculator()
self.progress_queue = queue.Queue()
# 初始化统一日志系统
self.logger = get_logger(__name__)
self._gui_handler = None # 将在 _create_log_panel 中设置
self._poll_progress_queue()
self.create_widgets()
self._apply_ui_config()
@@ -116,6 +122,14 @@ class DataExtractionTab(ttk.Frame):
self.log_text = LogText(parent, height=15, readonly=True)
self.log_text.pack(fill=tk.BOTH, expand=True)
# 设置 GUI 日志处理器,将 logging 输出桥接到 LogText 组件
self._gui_handler = GuiTextHandler(self.log_text)
self._gui_handler.setFormatter(logging.Formatter(
'%(asctime)s [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
))
self.logger.addHandler(self._gui_handler)
def _apply_ui_config(self):
try:
font_family = self.config.get("ui.font_family", "Microsoft YaHei UI")
@@ -219,15 +233,24 @@ class DataExtractionTab(ttk.Frame):
except: pass
def _update_log(self, message: str, level: str = "INFO"):
"""标准的日志更新方法"""
def update():
# 即使任务结束,只要是成功/错误消息也强制显示
if self.extracting or level in ["ERROR", "WARNING", "SUCCESS"]:
if level == "INFO": self.log_text.info(message)
elif level == "SUCCESS": self.log_text.success(message)
elif level == "WARNING": self.log_text.warning(message)
elif level == "ERROR": self.log_text.error(message)
self.after(0, update)
"""
标准的日志更新方法(兼容接口)
通过统一的 logging 系统输出日志,自动同时输出到控制台和 GUI。
Args:
message: 日志消息
level: 日志级别 (INFO, SUCCESS, WARNING, ERROR, DEBUG)
"""
# 将自定义级别映射到 logging 级别
level_upper = level.upper()
if level_upper == "SUCCESS":
# SUCCESS 映射到 INFO但在 UI 中仍显示为 SUCCESS
self.logger.info(message)
else:
# 其他级别直接映射
log_level = getattr(logging, level_upper, logging.INFO)
self.logger.log(log_level, message)
def _on_production_ids_changed(self, event=None):
if self.main_window: