repo_description: PC自动玩尘白，自动化代理，尘白禁区助手，自动钓鱼，信源解析，水弹，异星守护，迷宫
repo_topics: automation fishing snowbreak
code: import logging
  import sys
  
  from PyQt5.QtCore import QObject, pyqtSignal
  from PyQt5.QtWidgets import QTextBrowser
  
  
  class Stream(QObject):
      """
      自定义输出流，捕获 print 的输出
      """
      message = pyqtSignal(str)
  
      def __init__(self, original_stream):
          super().__init__()
          self.original_stream = original_stream  # 保留原始输出流
  
      def write(self, message):
          self.original_stream.write(message)
          # 发送html文本
          self.message.emit(str(message))
  
      def flush(self):
          self.original_stream.flush()
  
  
  class HtmlFormatter(logging.Formatter):
      """
      捕获的输出转换为适合控件显示的html格式
      """
      formats = {
          logging.DEBUG: "gray",
          logging.INFO: "green",
          logging.WARNING: "orange",
          logging.ERROR: "red",
          logging.CRITICAL: "purple"
      }
  
      def __init__(self, fmt="%(asctime)s - %(levelname)s - %(message)s", datefmt="%H:%M:%S"):
          super().__init__(fmt=fmt, datefmt=datefmt)
  
      def format(self, record):
          # 通过logger等级获取对应颜色
          color = self.formats.get(record.levelno)
          # logger内容获取
          message = super().format(record)
          # 返回对应的html文本
          return f'<span style="color: {color};">{message}</span><br/>'
  
  
  class LogMessageHandler(logging.Handler):
      """
      捕获 logger 的输出
      """
  
      def __init__(self, text_stream):
          super().__init__()
          self.text_stream = text_stream
          # 设置使用 HTML 格式化
          self.setFormatter(HtmlFormatter())
  
      def emit(self, record):
          # 调用format获取对应的html文本字符串
          msg = self.format(record)
          self.text_stream.write(msg)
  
  
  # 创建一个全局的logger实例，其他模块引用该实例来记录日志
  original_stdout = sys.stdout
  original_stderr = sys.stderr
  stdout_stream = Stream(original_stdout)
  stderr_stream = Stream(original_stderr)
  handler = LogMessageHandler(stdout_stream)
  # # 禁用 Tesseract 的日志输出
  # logging.getLogger('Tesseract').setLevel(logging.CRITICAL)
  logger = logging.getLogger()
  logger.addHandler(handler)
  logger.setLevel(logging.DEBUG)
  
  
  class Logger:
      def __init__(self, log_widget: QTextBrowser):
          self.log_widget = log_widget
  
          self.original_stdout = sys.stdout
          self.original_stderr = sys.stderr
          self.stdout_stream = Stream(self.original_stdout)
          self.stderr_stream = Stream(self.original_stderr)
          self.handler = LogMessageHandler(self.stdout_stream)
  
          self.logger = logging.getLogger()
          self.logger.addHandler(self.handler)
          self.logger.setLevel(logging.DEBUG)
          if self.log_widget:
              self.redirectOutput()
  
      def redirectOutput(self):
          # 普通输出
          sys.stdout = self.stdout_stream
          # 报错输出
          sys.stderr = self.stderr_stream
          # 将新消息信号连接到QTextEdit
          self.stdout_stream.message.connect(self.updateDisplay)
          self.stderr_stream.message.connect(self.updateDisplay)
  
      def updateDisplay(self, message):
          # 将消息添加到 QTextEdit，自动识别 HTML
          self.log_widget.insertHtml(message)
          self.log_widget.insertPlainText('\n')  # 为下一行消息留出空间
          self.log_widget.ensureCursorVisible()  # 滚动到最新消息
  