Files
playwrite/gui/widgets/log_handler.py
Misaka 3b7c00377f style: format all Python files with Black
Apply Black formatter to the entire codebase for consistent code style.

Co-Authored-By: Claude (glm-5) <noreply@anthropic.com>
2026-02-26 22:44:03 +08:00

123 lines
3.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
自定义 logging Handler将日志输出到 LogText 组件
"""
import logging
import re
from typing import Optional
from gui.widgets.log_text import LogText
class GuiTextHandler(logging.Handler):
"""
将日志输出到 GUI LogText 组件的 Handler
这个 Handler 桥接了 Python 标准 logging 模块和 GUI 的 LogText 组件,
使得使用 logging 模块的代码可以自动将日志输出到 GUI 界面。
"""
def __init__(self, log_text: Optional[LogText] = None):
"""
初始化 Handler
Args:
log_text: LogText 组件实例,可以为 None稍后通过 set_log_text 设置
"""
super().__init__()
self.log_text = log_text
# 映射 logging 级别到 LogText 级别
self.level_map = {
logging.INFO: "INFO",
logging.WARNING: "WARNING",
logging.ERROR: "ERROR",
logging.DEBUG: "DEBUG",
logging.CRITICAL: "ERROR",
}
def set_log_text(self, log_text: LogText):
"""
设置或更新 LogText 组件引用
Args:
log_text: LogText 组件实例
"""
self.log_text = log_text
def emit(self, record: logging.LogRecord):
"""
实现日志输出
Args:
record: logging.LogRecord 对象
"""
if not self.log_text:
return
try:
# 获取日志级别
level = self.level_map.get(record.levelno, "INFO")
# 只获取消息内容不包含时间戳和级别LogText.log() 会添加)
message = record.getMessage()
# 移除消息中可能存在的冗余级别标记(如 "[INFO] "、"[ERROR] " 等)
# 这是因为有些代码在消息中已经包含了级别标记
message = self._strip_redundant_level_prefix(message)
# 定义更新函数
def update():
"""在主线程中更新 GUI"""
try:
# LogText.log() 会自动添加时间戳和级别
self.log_text.log(message, level)
except Exception:
# 如果 log 失败,忽略错误避免递归
pass
# 尝试使用 after 确保在主线程更新
import tkinter as tk
try:
# 尝试获取主窗口
widget = self.log_text
while widget and widget.master:
if isinstance(widget.master, tk.Tk):
# 找到主窗口,使用 after 调度更新
widget.master.after(0, update)
return
widget = widget.master
# 如果找不到主窗口,直接调用(适用于非 GUI 模式或测试)
update()
except Exception:
# 如果线程调度失败,直接调用
update()
except Exception:
# 处理错误,避免影响主程序
self.handleError(record)
def _strip_redundant_level_prefix(self, message: str) -> str:
"""
移除消息开头的冗余级别标记
例如:"[INFO] 读取 ProductionID 文件" -> "读取 ProductionID 文件"
"[ERROR] 错误信息" -> "错误信息"
Args:
message: 原始消息
Returns:
清理后的消息
"""
# 常见的日志级别标记模式
level_pattern = r"^\[(?:INFO|WARNING|ERROR|DEBUG|CRITICAL|WARN|SUCCESS)\]\s*"
match = re.match(level_pattern, message)
if match:
# 移除匹配到的级别前缀
return message[match.end() :]
return message