PyQt5. Вывод консольных логов в QTextEdit с использованием кастомной цветовой схемы

В данной реализации логи без проблем валятся в консоль и виджит QTextEdit, но по понятным причинам всё выводится в одном цвете. Подскажите, как можно использовать туже цветовую (или какую-то другую) схему во вкладке History в виджите QTextEdit?

введите сюда описание изображения

# -*- coding: utf-8 -*-

import logging, sys
from PyQt5.QtGui import QFont, QTextCursor
from PyQt5.QtWidgets import (
    QApplication, QGridLayout, QTextEdit, QMainWindow, QTabWidget,
    QWidget, QGroupBox, QHBoxLayout, QVBoxLayout, QPushButton
)

LOG_FORMAT = "[%(asctime)s]:[%(filename)s:%(lineno)d] - %(levelname)s - %(name)s - %(message)s"


class CustomLogFormatter(logging.Formatter):

    magenta  = "\x1b[95m"
    cyan     = "\x1b[96m"
    yellow   = "\x1b[93m"
    red      = "\x1b[31m"
    bold_red = "\x1b[31;1m"
    reset    = "\x1b[0m"

    FORMATS = {
        logging.DEBUG   : magenta + LOG_FORMAT + reset,
        logging.INFO    : cyan + LOG_FORMAT + reset,
        logging.WARNING : yellow + LOG_FORMAT + reset,
        logging.ERROR   : red + LOG_FORMAT + reset,
        logging.CRITICAL: bold_red + LOG_FORMAT + reset
    }

    def format(self, message):

        log_fmt = self.FORMATS.get(message.levelno)
        formatter = logging.Formatter(log_fmt)
        return formatter.format(message)


class MainApp(QMainWindow):

    """
        ---=== Main Application Window Interface Class ===---
        """

    def __init__(self):

        super().__init__()

        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)

        self.resize(800, 500)
        self.setWindowTitle("Application")

        self.main_app_build()

    def main_app_build(self):

        tab1 = Tab1()
        tab_history = TabHistory()

        self.tabs = QTabWidget()
        self.tabs.addTab(tab1, "Tab1")
        self.tabs.addTab(tab_history, "History")

        g_layout = QGridLayout(self.centralWidget)
        g_layout.addWidget(self.tabs)

        logger.info("Application Run")


class Tab1(QWidget):
    """
        ---=== Tab CUCM - Main Interface Class of CUCM Tab ===---
        """

    def __init__(self, parent=None):

        super().__init__(parent)

        tasks_buttons = QPushButton("LOG RUN")
        tasks_buttons.clicked.connect(self.log_gen)

        self.h_layout = QHBoxLayout(self)
        self.h_layout.addWidget(tasks_buttons)

    def log_gen(self):

        logger.debug("DEBUG BLA BLA BLA")
        logger.info("INFO BLA BLA BLA")
        logger.warning("WARNING BLA BLA BLA")
        logger.error("ERROR BLA BLA BLA")
        logger.critical("CRITICAL BLA BLA BLA")


class TabHistory(QWidget):

    def __init__(self, parent=None):

        super(TabHistory, self).__init__(parent)

        self.history_text = QTextEdit()
        self.history_text.setStyleSheet("""
            QTextEdit {
                background-color: #000;
                color: #00ff00
            }""")

        h_layout = QHBoxLayout(self)
        h_layout.addWidget(self.history_text)

        history_box = QGroupBox()
        history_box.setTitle("&History")
        history_box.setFont(QFont("Helvetica", 10, QFont.Normal, italic=False))
        history_box.setLayout(h_layout)

        v_layout = QVBoxLayout(self)
        v_layout.addWidget(history_box)

        sys.stdout.write = self.request_std(sys.stdout.write)
        sys.stderr.write = self.request_std(sys.stderr.write)

    def request_std(self, func):

        def inner(inputStr):

            cursor = QTextCursor(self.history_text.document())
            cursor.setPosition(0)
            self.history_text.setTextCursor(cursor)

            self.history_text.insertPlainText(inputStr)
            return func(inputStr)

        return inner
    
    
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

stream_handler = logging.StreamHandler()
stream_handler.setFormatter(CustomLogFormatter())
stream_handler.setLevel(logging.DEBUG)

logger.addHandler(stream_handler)

logger = logging.getLogger("* Test App *")


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = MainApp()
    ex.show()
    sys.exit(app.exec_())

Ответы (1 шт):

Автор решения: Luarvick

Спасибо за подсказку @insolor. Проблему решил добавлением класса QTextEditLogger (https://stackoverflow.com/questions/28655198/best-way-to-display-logs-in-pyqt) и изменением класса TabHistory. Было бы интерерсно глянуть другие варианты решения задачи.

введите сюда описание изображения

Измененный код.

class QTextEditLogger(logging.Handler):

    def __init__(self, parent):

        super().__init__()
        self.widget = QTextEdit(parent)
        self.widget.setReadOnly(True)
        self.widget.setStyleSheet("""
            QTextEdit {
                background-color: #000;
            }""")

    def emit(self, record):

        log_message = self.format(record)
        if "DEBUG" in log_message:
            text = f"""<span style='color:#ff00ff;'>{log_message}</span>"""
        elif "INFO" in log_message:
            text = f"""<span style='color:#00ffff;'>{log_message}</span>"""
        elif "WARNING" in log_message:
            text = f"""<span style='color:#ffff00;'>{log_message}</span>"""
        elif "ERROR" in log_message or "CRITICAL" in log_message:
            text = f"""<span style='color:#ff0000;'>{log_message}</span>"""
        self.widget.append(text)

class TabHistory(QWidget):

    def __init__(self, parent=None):
        super(TabHistory, self).__init__(parent)


        custom_handler = QTextEditLogger(self)
        custom_handler.setFormatter(logging.Formatter(LOG_FORMAT))
        custom_handler.setLevel(logging.DEBUG)

        logging.getLogger().addHandler(custom_handler)

        history_text = custom_handler.widget

        h_layout = QHBoxLayout(self)
        h_layout.addWidget(history_text)

        history_box = QGroupBox()
        history_box.setTitle("&History")
        history_box.setFont(QFont("Helvetica", 10, QFont.Normal, italic=False))
        history_box.setLayout(h_layout)

        v_layout = QVBoxLayout(self)
        v_layout.addWidget(history_box)
→ Ссылка