SQLite3+logging+PyQt5+fuzzywuzzy 日志数据库高亮/等级筛选/模糊查询/时间范围筛选 | python

2023-02-06 10:13:36 浏览数 (3)

功能实现:

  1. 日志保存与读取 SQLite3
  2. 等级筛选 SQL
  3. 模糊查询 fuzzywuzzy
  4. 时间范围筛选 time
  5. 日志内容语法高亮 PyQt5.Qsci
  6. 日志具体信息弹窗Dialog (表单内容双击事件) PyQt5
  7. logging Handler类,此程序可作为模块引入

文章目录

  • 1. SQLite3 数据库
        • 知识点
  • 2. fuzzywuzzy.fuzz 模糊搜索
        • 知识点
  • 3. logging 日志
        • 知识点
  • 4. PyQt5.Qsci 语法高亮 与 PyQt5
      • 事件
  • 5. functions.py
  • 使用方法

1. SQLite3 数据库

SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。 RUNOOB | SQLite - Python

知识点
  • *sqlite3.connect(database: str [,timeout , args]) -> connection 打开一个到 SQLite 数据库文件 database ( 如果给定的数据库名称 filename 不存在,则该调用将创建一个数据库 ) ":memory:" 来在 RAM 中打开一个到 database 的数据库连接。 sqlite3.connect(..., check_same_thread=False) 可以在多个线程中获取/提交数据库信息
  • connection.cursor([cursorClass]) -> cursor
  • cursor.execute(sql [, __iter: iterable]) -> return value from database. 执行一个 SQL 语句 - 该 SQL 语句可以被参数化__iter cursor.execute(“insert into people values ( ?, ?)”, ( var1, var2))
  • connection.commit() -> None 该方法提交当前的事务。 (中途生成 *.dbjourney文件)

我专门定义了一个SQliteIO类管理数据库:

代码语言:javascript复制
db_filename = "database/database.db"

class SQliteIO(object):
    def __init__(self):
        self.db = sqlite3.connect(db_filename, check_same_thread=False)
        self.cursor = self.db.cursor()
        self.init_db()
    
    def __del__(self):
        self.db.close()

    def reset_db(self):  # thread-in
        self.db.close()
        if os.path.isfile(db_filename):
            os.remove(db_filename)
        self.db = sqlite3.connect(db_filename, check_same_thread=False)
        self.cursor = self.db.cursor()

    def init_db(self):  # thread-in
        try:
            self.cursor.execute('create table logging(time FLOAT ,level INTEGER, '
                                f'data VARCHAR({sys.maxsize}), name VARCHAR(1024))')
            # self.cursor.execute("create table user(username VARCHAR(12), password VARCHAR(10), time FLOAT,
            # id INTEGER)")
            self.db.commit()
        except sqlite3.OperationalError:
            pass
        except sqlite3.DatabaseError:
            self.reset_db()
            self.init_db()

    @staticmethod
    def getSize() -> str:
        return convert(os.path.getsize(db_filename), True) if os.path.isfile(db_filename) else convert(0)

    def commit(self, __sql="", __params: (list, tuple) = ()):  # thread-in
        try:
            data = self.cursor.execute(__sql, __params)
            self.db.commit()
            return data
        except (sqlite3.ProgrammingError, AttributeError):
            return None
        except sqlite3.DatabaseError:
            self.reset_db()
            return None

2. fuzzywuzzy.fuzz 模糊搜索

  • fuzz主要用于两字符串之间匹配

[ i ] 第三方库 conda install fuzzywuzzypip install fuzzywuzzy

知识点

两个模块:fuzz, process fuzz主要用于两字符串之间匹配,process主要用于搜索排序。 fuzz.ratio(s1,s2)直接计算s2和s2之间的相似度,返回值为0-100,100表示完全相同; fuzz.partial_ratio(S1,S2)部分匹配,如果S1是S2的子串依然返回100; fuzz.token_sort_ratio(S1,S2)只比较S1,S2单词是否相同,不考虑词语之间的顺序fuzz.token_set_ratio(S1,S2)相比fuzz.token_sort_ratio不考虑词语出现的次数process.extract(S1, ListS,limit=n),表示从列表ListS中找出Top n与S1最相似的句子; process.extractOne(S1,ListS),返回最相似的一个

  • 选自 https://www.cnblogs.com/ly570/p/10935454.html
代码语言:javascript复制
class SQliteHandler(logging.Handler):
	...
	
    @staticmethod
    def fuzzyfinder(content, collections):
        return [v[1] for v in
                sorted([(fuzz.token_set_ratio(content, data), data) for data in collections],
                       key=lambda x: x[0], reverse=True)]  # 按相似度 排序

3. logging 日志

知识点

相较于fuzzywuzzy, logging模块是再熟悉不过了, 我也就不在细讲

  • https://blog.csdn.net/pansaky/article/details/90710751
  • https://www.cnblogs.com/xianyulouie/p/11041777.html
  • 主要是继承logging.Handler类
代码语言:javascript复制
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

LOGGING_LEVEL = {"NOTSET": logging.NOTSET,
                 "DEBUG": logging.DEBUG,
                 "INFO": logging.INFO,
                 "WARNING": logging.WARNING,
                 "ERROR": logging.ERROR,
                 "CRITICAL": logging.CRITICAL}
LOGGING_LEVEL_INDEX = {logging.NOTSET: "NOTSET",
                       logging.DEBUG: "DEBUG",
                       logging.INFO: "INFO",
                       logging.WARNING: "WARNING",
                       logging.ERROR: "ERROR",
                       logging.CRITICAL: "CRITICAL"}

class SQliteHandler(logging.Handler):
    def __init__(self):
        self.connection: callable = None
        self.sqlite = SQliteIO()
        super(SQliteHandler, self).__init__()

    def connect(self, connection: callable):
        self.connection = connection

    def emit(self, record: logging.LogRecord) -> None:
        __stamp = round(time.time(), 2)
        self.sqlite.commit(f"INSERT INTO logging(time, level, data, name) VALUES (?, ?, ?, ?)",
                           (__stamp, record.levelno, record.msg, record.name))
        if self.connection is not None:
            self.connection()

    @staticmethod
    def fuzzyfinder(content, collections):
        return [v[1] for v in
                sorted([(fuzz.token_set_ratio(content, data), data) for data in collections],
                       key=lambda x: x[0], reverse=True)]  # 按相似度 排序

    # @timeit("Logging Data", logger)
    def getData(self, level: (int, str) = logging.NOTSET, content=str()):
        if isinstance(level, str):
            level = LOGGING_LEVEL[level]
        datas = [x for x in
                 self.sqlite.commit("SELECT time, level, data, name FROM logging where level >= ?", (level,))]
        if isinstance(content, str) and content:
            return sum([sorted([data for data in datas if data[2] == element], key=lambda x: x[0], reverse=True)
                        for element in SQliteHandler.fuzzyfinder(content, set([x[2] for x in datas]))], [])
            # 重复元素按时间排序, 时间越近越靠前
        else:
            return sorted(datas, key=lambda x: x[1], reverse=True)

4. PyQt5.Qsci 语法高亮 与 PyQt5

PythonSci代码 来自 https://blog.csdn.net/hwd00001/article/details/103049588 QLoggingTableWidget代码 来自 UI

代码语言:javascript复制
class QLoggingTableWidget(QtWidgets.QWidget):
    class PythonSci(QsciScintilla):
        """ Modules: PyQt5, qscintilla
        PythonSci代码 来自 https://blog.csdn.net/hwd00001/article/details/103049588"""

        class highlight(QsciLexerPython):
            def __init__(self, parent):
                QsciLexerPython.__init__(self, parent)
                font = QtGui.QFont()
                font.setFamily('Consolas')
                font.setPointSize(12)
                font.setFixedPitch(True)
                self.setFont(font)
                self.setColor(QtGui.QColor(0, 0, 0))
                self.setPaper(QtGui.QColor(255, 255, 255))
                self.setColor(QtGui.QColor("#00FF00"), QsciLexerPython.ClassName)
                self.setColor(QtGui.QColor("#B0171F"), QsciLexerPython.Keyword)
                self.setColor(QtGui.QColor("#00FF00"), QsciLexerPython.Comment)
                self.setColor(QtGui.QColor("#FF00FF"), QsciLexerPython.Number)
                self.setColor(QtGui.QColor("#0000FF"), QsciLexerPython.DoubleQuotedString)
                self.setColor(QtGui.QColor("#0000FF"), QsciLexerPython.SingleQuotedString)
                self.setColor(QtGui.QColor("#288B22"), QsciLexerPython.TripleSingleQuotedString)
                self.setColor(QtGui.QColor("#288B22"), QsciLexerPython.TripleDoubleQuotedString)
                self.setColor(QtGui.QColor("#0000FF"), QsciLexerPython.FunctionMethodName)
                self.setColor(QtGui.QColor("#191970"), QsciLexerPython.Operator)
                self.setColor(QtGui.QColor("#000000"), QsciLexerPython.Identifier)
                self.setColor(QtGui.QColor("#00FF00"), QsciLexerPython.CommentBlock)
                self.setColor(QtGui.QColor("#0000FF"), QsciLexerPython.UnclosedString)
                self.setColor(QtGui.QColor("#FFFF00"), QsciLexerPython.HighlightedIdentifier)
                self.setColor(QtGui.QColor("#FF8000"), QsciLexerPython.Decorator)
                self.setFont(QtGui.QFont('Courier', 12, weight=QtGui.QFont.Bold), 5)
                self.setFont(QtGui.QFont('Courier', 12, italic=True), QsciLexerPython.Comment)

        def __init__(self, text, parent=None):
            super(QLoggingTableWidget.PythonSci, self).__init__(parent)
            font = QtGui.QFont()
            font.setFamily('Consolas')
            font.setPointSize(12)
            font.setFixedPitch(True)
            self.setFont(font)
            self.setFont(font)
            self.setUtf8(True)
            self.setMarginsFont(font)
            self.setMarginWidth(0, len(str(len(self.text().split('n')))) * 20)
            self.setMarginLineNumbers(0, True)
            self.setEdgeMode(QsciScintilla.EdgeLine)
            self.setEdgeColumn(80)
            self.setEdgeColor(QtGui.QColor(0, 0, 0))
            self.setBraceMatching(QsciScintilla.StrictBraceMatch)
            self.setIndentationsUseTabs(True)
            self.setIndentationWidth(4)
            self.setTabIndents(True)
            self.setAutoIndent(True)
            self.setBackspaceUnindents(True)
            self.setTabWidth(4)
            self.setCaretLineVisible(True)
            self.setCaretLineBackgroundColor(QtGui.QColor('#FFFFCD'))
            self.setIndentationGuides(True)
            self.setFolding(QsciScintilla.PlainFoldStyle)
            self.setMarginWidth(2, 12)
            self.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPEN)
            self.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDER)
            self.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
            self.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDEREND)
            self.setMarkerBackgroundColor(QtGui.QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEREND)
            self.setMarkerForegroundColor(QtGui.QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEREND)
            self.setMarkerBackgroundColor(QtGui.QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
            self.setMarkerForegroundColor(QtGui.QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
            self.setAutoCompletionSource(QsciScintilla.AcsAll)
            self.setAutoCompletionCaseSensitivity(True)
            self.setAutoCompletionReplaceWord(False)
            self.setAutoCompletionThreshold(1)
            self.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit)
            self.lexer = QLoggingTableWidget.PythonSci.highlight(self)
            self.setLexer(self.lexer)
            self.mod = False
            self.autoCompleteFromAll()
            self.setReadOnly(True)
            self.setText(text)

    class LoggingInformation(QtWidgets.QDialog):
        def __init__(self, str_time, level, content, name, parent=None):
            super().__init__(parent)
            self.setObjectName("LoggingInformation")
            self.resize(640, 800)
            font = QtGui.QFont()
            font.setFamily("Consolas")
            self.setFont(font)
            icon = QtGui.QIcon()
            icon.addPixmap(QtGui.QPixmap("images/fileRecord.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
            self.setWindowIcon(icon)
            self.gridLayout = QtWidgets.QGridLayout(self)
            self.gridLayout.setObjectName("gridLayout")
            self.label_4 = QtWidgets.QLabel(self)
            self.label_4.setStyleSheet("color: rgb(0, 85, 255);n"
                                       "font: 9pt "Consolas";")
            self.label_4.setObjectName("label_4")
            self.gridLayout.addWidget(self.label_4, 1, 1, 1, 1)
            self.label_6 = QtWidgets.QLabel(self)
            self.label_6.setStyleSheet("color: rgb(255, 170, 0);n"
                                       "font: 9pt "Consolas";")
            self.label_6.setObjectName("label_6")
            self.gridLayout.addWidget(self.label_6, 2, 1, 1, 1)
            self.label_3 = QtWidgets.QLabel(self)
            self.label_3.setObjectName("label_3")
            self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
            self.label_7 = QtWidgets.QLabel(self)
            self.label_7.setObjectName("label_7")
            self.gridLayout.addWidget(self.label_7, 3, 0, 1, 1)
            self.label = QtWidgets.QLabel(self)
            self.label.setObjectName("label")
            self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
            self.label_2 = QtWidgets.QLabel(self)
            self.label_2.setStyleSheet(
                "color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(255, 255, 0, 255), "
                "stop:1 rgba(0, "
                "185, 255, 255));n "
                "font: 9pt "Consolas";")
            self.label_2.setObjectName("label_2")
            self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)
            self.label_5 = QtWidgets.QLabel(self)
            self.label_5.setObjectName("label_5")
            self.gridLayout.addWidget(self.label_5, 2, 0, 1, 1)
            self.widget = QLoggingTableWidget.PythonSci(content, self)
            self.widget.setObjectName("widget")
            self.gridLayout.addWidget(self.widget, 3, 1, 1, 1)

            _translate = QtCore.QCoreApplication.translate
            self.setWindowTitle(_translate("LoggingInformation", "日志信息"))
            self.label_4.setText(_translate("LoggingInformation", f"{level}"))
            self.label_6.setText(_translate("LoggingInformation", f"{name}"))
            self.label_3.setText(_translate("LoggingInformation", "等级:"))
            self.label_7.setText(_translate("LoggingInformation", "日志信息:"))
            self.label.setText(_translate("LoggingInformation", "时间:"))
            self.label_2.setText(_translate("LoggingInformation", f"{str_time}"))
            self.label_5.setText(_translate("LoggingInformation", "执行文件地址:"))

            QtCore.QMetaObject.connectSlotsByName(self)
            self.exec()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.datas = []
        self.setObjectName("QLoggingTableWidget")
        self.resize(480, 840)
        font = QtGui.QFont()
        font.setFamily("Consolas")
        self.setFont(font)
        self.verticalLayout = QtWidgets.QVBoxLayout(self)
        self.verticalLayout.setObjectName("verticalLayout")
        self.formLayout = QtWidgets.QFormLayout()
        self.formLayout.setHorizontalSpacing(0)
        self.formLayout.setObjectName("formLayout")
        self.searchLabel = QtWidgets.QLabel(self)
        self.searchLabel.setMaximumSize(QtCore.QSize(30, 30))
        self.searchLabel.setPixmap(QtGui.QPixmap("images/search.png"))
        self.searchLabel.setScaledContents(True)
        self.searchLabel.setObjectName("searchLabel")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.searchLabel)
        self.searchInputBox = QtWidgets.QLineEdit(self)
        self.searchInputBox.setClearButtonEnabled(True)
        self.searchInputBox.setObjectName("searchInput-box")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.searchInputBox)
        self.filterLabel = QtWidgets.QLabel(self)
        self.filterLabel.setMaximumSize(QtCore.QSize(30, 30))
        self.filterLabel.setPixmap(QtGui.QPixmap("images/filter.png"))
        self.filterLabel.setScaledContents(True)
        self.filterLabel.setObjectName("filterLabel")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.filterLabel)
        self.comboBox = QtWidgets.QComboBox(self)
        self.comboBox.setObjectName("comboBox")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.comboBox)
        self.timeRadioButton = QtWidgets.QRadioButton(self)
        self.timeRadioButton.setObjectName("radioButton")
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.timeRadioButton)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.startDateTimeEdit = QtWidgets.QDateTimeEdit(self)
        self.startDateTimeEdit.setObjectName("dateTimeEdit")
        self.horizontalLayout.addWidget(self.startDateTimeEdit)
        self.label = QtWidgets.QLabel(self)
        self.label.setObjectName("label")
        self.horizontalLayout.addWidget(self.label)
        self.endDateTimeEdit = QtWidgets.QDateTimeEdit(self)
        self.endDateTimeEdit.setObjectName("dateTimeEdit_2")
        self.horizontalLayout.addWidget(self.endDateTimeEdit)
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.formLayout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout)
        self.verticalLayout.addLayout(self.formLayout)
        self.loggingTableWidget = QtWidgets.QTableWidget(self)
        self.loggingTableWidget.setObjectName("loggingTableWidget")
        self.loggingTableWidget.setColumnCount(0)
        self.loggingTableWidget.setRowCount(0)
        self.verticalLayout.addWidget(self.loggingTableWidget)

        QtCore.QMetaObject.connectSlotsByName(self)

        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("QLoggingTableWidget", "Form"))
        self.searchLabel.setWhatsThis(_translate("QLoggingTableWidget", "<html><head/><body><p>模糊搜索</p></body></html>"))
        self.searchInputBox.setToolTip(
            _translate("QLoggingTableWidget", "<html><head/><body><p>模糊搜索</p></body></html>"))
        self.filterLabel.setWhatsThis(_translate("QLoggingTableWidget", "<html><head/><body><p>等级筛选</p></body></html>"))
        self.comboBox.setWhatsThis(_translate("QLoggingTableWidget", "<html><head/><body><p>等级筛选</p></body></html>"))
        self.timeRadioButton.setText(_translate("QLoggingTableWidget", "起始时间"))
        self.label.setText(_translate("QLoggingTableWidget", "-"))
        self.loggingTableWidget.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
        self.comboBox.addItems(list(LOGGING_LEVEL.keys())[1:])
        self.loggingTableWidget.setColumnCount(4)
        self.loggingTableWidget.setHorizontalHeaderLabels(["时间", "等级", "数据", "执行地址"])
        self.loggingTableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)  # 禁止编辑
        self.loggingTableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)  # 设置表格整行选中
        self.setDateTimeEditEnabled(False)

        self.timeRadioButton.clicked.connect(self.timeRadio)
        self.loggingTableWidget.doubleClicked.connect(self.tableClicked)
        self.comboBox.currentIndexChanged.connect(self.updateLoggingTable)
        self.searchInputBox.textChanged.connect(self.updateLoggingTable)
        self.timeRadioButton.clicked.connect(self.updateLoggingTable)
        self.startDateTimeEdit.timeChanged.connect(self.updateLoggingTable)
        self.endDateTimeEdit.timeChanged.connect(self.updateLoggingTable)
        SQliteLoggingHandler.connect(self.updateLoggingTable)

        self.startDateTimeEdit.setDate(QtCore.QDate.currentDate())
        self.endDateTimeEdit.setDate(QtCore.QDate.currentDate())
        self.endDateTimeEdit.setTime(QtCore.QTime.currentTime())

        self.updateLoggingTable()

    def timeRadio(self, *args): # 这些代码一会发
    def tableClicked(self, index: QtCore.QModelIndex, *args):
    def setDateTimeEditEnabled(self, a0: bool) -> None:
    def getFilter(self):
    def updateLoggingTable(self, *args):
    @staticmethod
    def colorful(level) -> QtGui.QColor:

事件

一共绑定了8个事件

timeRadioButton.clicked.connect(self.timeRadio) 单选框点击事件绑定是否开启时间范围筛选

代码语言:javascript复制
def timeRadio(self, *args):
    self.setDateTimeEditEnabled(self.timeRadioButton.isChecked())

self.loggingTableWidget.doubleClicked.connect(self.tableClicked) 表格左键双击绑定 具体日志信息Dialog 的展示

代码语言:javascript复制
    def tableClicked(self, index: QtCore.QModelIndex, *args):
        self.LoggingInformation(*self.datas[index.row()], self)

self.comboBox.currentIndexChanged.connect(self.updateLoggingTable) self.searchInputBox.textChanged.connect(self.updateLoggingTable) self.timeRadioButton.clicked.connect(self.updateLoggingTable) self.startDateTimeEdit.timeChanged.connect(self.updateLoggingTable) self.endDateTimeEdit.timeChanged.connect(self.updateLoggingTable) SQliteLoggingHandler.connect(self.updateLoggingTable) 下拉框(等级)改变搜索框文字改变起始时间框改变是否启用时间范围筛选日志更新 6个事件绑定更新表格

代码语言:javascript复制
    def getFilter(self):
        search = self.searchInputBox.text().strip()
        level = LOGGING_LEVEL[self.comboBox.currentText()]
        if self.timeRadioButton.isChecked():
            startTime = time.mktime(time.strptime(self.startDateTimeEdit.text(), "%Y/%m/%d %H:%M"))
            endTime = time.mktime(time.strptime(self.endDateTimeEdit.text(), "%Y/%m/%d %H:%M"))
            return [(time.strftime("%m-%d %H:%M:%S",
                                   time.localtime(stamp)),
                     LOGGING_LEVEL_INDEX[levelno],
                     data,
                     name) for stamp, levelno, data, name in SQliteLoggingHandler.getData(level, search)
                    if startTime <= stamp <= endTime]
        else:
            return [(time.strftime("%m-%d %H:%M:%S",
                                   time.localtime(stamp)),
                     LOGGING_LEVEL_INDEX[levelno],
                     data,
                     name) for stamp, levelno, data, name in SQliteLoggingHandler.getData(level, search)]

    def updateLoggingTable(self, *args):
        datas = self.getFilter()
        self.datas = datas
        self.loggingTableWidget.clear()
        self.loggingTableWidget.setHorizontalHeaderLabels(["时间", "等级", "数据", "执行地址"])
        self.loggingTableWidget.setRowCount(len(datas))
        for _row in range(len(datas)):
            row = datas[_row]
            for _col in range(len(row)):
                col: str = row[_col]
                item = QtWidgets.QTableWidgetItem(col)
                if _col == 0:  # time
                    item.setForeground(QtGui.QColor(50, 50, 225))
                if _col == 1:  # level
                    item.setForeground(self.colorful(col))
                self.loggingTableWidget.setItem(_row, _col, item)

    @staticmethod
    def colorful(level) -> QtGui.QColor:
        return QtGui.QColor(*{"NOTSET": (195, 195, 195),
                              "DEBUG": (128, 128, 128),
                              "INFO": (0, 0, 255),
                              "WARNING": (255, 128, 64),
                              "ERROR": (255, 0, 0),
                              "CRITICAL": (255, 0, 128)}.get(level))

5. functions.py

此文章隶属于ServerProject项目, 大部分依赖文件于此.

代码语言:javascript复制
import time
base = 1024


def _conv(value: (float, int)) -> str:
    value = float(value)
    if value.is_integer():
        return str(int(value))
    else:
        return str(round(value, 1))


def ignore(function):
    def _exec_func(*args, **kwargs):
        try:
            return function(*args, **kwargs)
        except:
            pass
    return _exec_func


def convert(byte, fine=False):
    """
    位 bit (比特)(Binary Digits):存放一位二进制数,即 0 或 1,最小的存储单位。
    字节 byte:8个二进制位为一个字节(B),最常用的单位。
    其中1024=2^10 ( 2 的10次方),
    1KB (Kilo byte 千字节)=1024B,
    1MB (Mega byte 兆字节 简称“兆”)=1024KB,
    1GB (Giga byte 吉字节 又称“千兆”)=1024MB,
    1TB (Trillion byte 万亿字节 太字节)=1024GB,
    1PB(Peta byte 千万亿字节 拍字节)=1024TB,
    1EB(Exa byte 百亿亿字节 艾字节)=1024PB"""
    if not isinstance(byte, (int, float)):
        byte = len(byte)
    DEI = f"{byte} bytes"
    units = ["b",
             "Kb",
             "Mb",
             "Gb",
             "Tb",
             "Pb",
             "Eb"]
    index = 0
    while True:
        if byte < 1024 or index   1 >= len(units):
            break
        byte /= base
        index  = 1

    if fine:
        return f"{_conv(byte)}{units[index]}({DEI})"
    else:
        return f"{_conv(byte)}{units[index]}"


def timeit(objname: str, logger, ign=True, _show_detail=True):
    def setup_function(func_name):
        def _exec_function(*args, **kwargs):
            start_time = time.time()
            _resp = func_name(*args, **kwargs)
            if _show_detail:
                logger.debug("Execute the function %s%s, timeit %0.3f" % (
                    objname.title(), "" if ign else f" (at {str(func_name)})", time.time() - start_time))
            return _resp
        return _exec_function
    return setup_function


def to_logging(logger):
    def log(command):
        def _exec_func(*args, **kwargs):
            try:
                _result = command(*args, **kwargs)
                if _result is None:
                    return True
                return _result
            except:
                logger.exception(str())
        return _exec_func
    return log

使用方法

QLoggingTableWidget继承于QWidget, 因此, 直接显示或添加父类至窗口上都可.

代码语言:javascript复制
from sqlite_handler import SQliteLoggingHandler, QLoggingTableWidget
logger = logging.getLogger(...)
logger.addHandler(SQliteLoggingHandler)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle("fusion")
    ...
    Qtable = QLoggingTableWidget()
    Qtable.show()
    sys.exit(app.exec_())

0 人点赞