debug, 调试时用
info, 输出普通的信息(程序按照预期执行)
warning, 警告信息
error, 程序出现的一些错误
critical,程序无法执行的错误。
设置级别为info时,只会输出info及更高的级别的信息。
import logging
logging.basicConfig(level=logging.INFO,
format="%(asctime)s-%(levelname)s-%(message)s-%(name)s-%(filename)s-%(pathname)s-%(funcName)s-%(lineno)s")
# 输出信息到控制台
logging.info("测试logging...")
# 在debug时,设置为debug级别,以下信息全部输出
logging.debug("这里是正常执行的...")
logging.info("测试logging...")
logging.warning("警告信息...")
logging.error("错误信息...")
logging.critical("严重错误...")
2. 输出日志到文件中
# 配置只能写一行,多行则第一行生效
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s", filename="./test.log", filemode="a")
# 追加到文件中
logging.info("输出日志到文件中")
步骤:
案例:
# 实例化日志记录器
myLogger = logging.Logger("laufing") # give a name %(name)s
# myLogger2 = logging.getLogger(__name__) 一般使用getLogger实例化对象,并最终setLevel后才可以打印日志
# 实例化日志处理器
handler = logging.FileHandler("test.log", mode="a", encoding="gbk") # output to test.log windows use gbk
# handler2 = logging.StreamHandler() # output to console
# 日志处理器 添加 级别、格式
# handler.setLevel(logging.INFO)
handler.setFormatter(logging.Formatter("%(asctime)s %(message)s"))
# 日志记录器 添加处理器
myLogger.addHandler(handler)
myLogger.setLevel(logging.INFO)
# 输出信息
myLogger.info("自定义日志记录器...")
一个日志记录器还可以添加多个日志处理器
如图,将日志内容输出到指定的QTextBrowser控件中,并根据不同的级别设置不同的颜色。
debug --gray
info – black
warning – yellow
error – red
critical – red
注意使用子线程,否则界面会卡死(主线程阻塞)
import sys
import logging
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import QThread, Signal
from ui.log_case import Ui_Form
# 自定义日志处理器
class MyHandler(logging.Handler):
colors = {
10: "gray",
20: "black",
30: "yellow",
40: "red",
50: "red" # 数值为日志的级别
}
def __init__(self, level, target_ui=None):
super(MyHandler, self).__init__(level)
self.target_ui = target_ui
self.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
def emit(self, record):
# logger.info 触发emit,并且可以从record中获取日志级别
print("record:", record.levelname) # 如 "INFO"
msg = self.format(record)
color = self.colors.get(self.level)
# QTextBrowser 追加内容并设置字体颜色
self.target_ui.setTextColor(color)
self.target_ui.append(msg)
self.target_ui.moveCursor(QTextCursor.End)
self.target_ui.setStyleSheet("QTextBrowser{font-size: 16px;}")
# 自定义日志记录器
class MyLogger(logging.Logger):
def __init__(self, name):
super(MyLogger, self).__init__(name)
handler = MyHandler(logging.INFO)
self.addHandler(handler)
def debug(self, msg, target_ui):
# 需要修改Handler的日志级别和target_ui
if not self.check_level(logging.DEBUG):
return
for handler in self.handlers:
handler.setLevel(logging.DEBUG)
handler.target_ui = target_ui
# 触发Handler的emit方法
super(MyLogger, self).debug(msg)
def info(self, msg, target_ui):
# 需要修改Handler的日志级别和target_ui
if not self.check_level(logging.INFO):
return
for handler in self.handlers:
handler.setLevel(logging.INFO)
handler.target_ui = target_ui
# 触发Handler的emit方法
super(MyLogger, self).info(msg)
def warning(self, msg, target_ui):
# 需要修改Handler的日志级别和target_ui
if not self.check_level(logging.WARNING):
return
for handler in self.handlers:
handler.setLevel(logging.WARNING)
handler.target_ui = target_ui
# 触发Handler的emit方法
super(MyLogger, self).warning(msg)
def error(self, msg, target_ui):
# 需要修改Handler的日志级别和target_ui
if not self.check_level(logging.ERROR):
return
for handler in self.handlers:
handler.setLevel(logging.ERROR)
handler.target_ui = target_ui
# 触发Handler的emit方法
super(MyLogger, self).error(msg)
def critical(self, msg, target_ui):
# 需要修改Handler的日志级别和target_ui
if not self.check_level(logging.CRITICAL):
return
for handler in self.handlers:
handler.setLevel(logging.CRITICAL)
handler.target_ui = target_ui
# 触发Handler的emit方法
super(MyLogger, self).critical(msg)
def check_level(self, expire_level):
""" 检查日志是否可以输出 """
if self.level > expire_level
return False
return True
# 子线程类
class SubThread(QThread):
def __init__(self, func, args, name=None):
QThread.__init__(self)
self.func = func
self.args = args
if name is not None:
self.name = name
self.finished.connect(self.deleteLater)
def run(self):
self.func(*self.args)
def func(*args):
# 将信号传入子线程
key, output_log_signal, notify_signal = args
t = 1
while t < 5:
print(f"{key}")
QThread.sleep(1)
output_log_signal.emit(f"{key} 返回数据 {t}")
t += 1
notify_signal.emit(f"{key}")
class MyWindow(QWidget):
workers = {}
# 定义信号,注意使用信号时任何地方不能使用emit变量,防止覆盖
output_log_signal = Signal(str)
notify_signal = Signal(str)
def __init__(self, logger, title="laufing"):
super(MyWindow, self).__init__()
# 窗口的尺寸及居中
self.resize(800, 600)
desk = QDesktopWidget().geometry()
width, height = desk.width(), desk.height()
self.move(width//2 - self.width()//2, height//2 - self.height()//2)
# 窗口标题
self.setWindowTitle(title)
self.setWindowIcon(QIcon("./imgs/dog.jpg"))
self._ui = Ui_Form()
self._ui.setupUi(self)
self.logger = logger
self.set_ui()
def set_ui(self):
self._ui.thread1_btn.clicked.connect(self.thread1)
self._ui.thread2_btn.clicked.connect(self.thread2)
# close() 触发closeEvent 关闭父窗口及其子窗口
self._ui.exit_btn.clicked.connect(self.close)
self.output_log_signal.connect(self.output_log)
self.notify_signal.connect(self.do_clean)
def do_clean(self, key):
# 结束后,删除子线程对象
self.workers.pop(key)
def thread1(self):
self.workers["thread1"] = SubThread(func, args=("thread1", self.output_log_signal, self.notify_signal))
self.workers["thread1"].start()
def thread2(self):
self.workers["thread2"] = SubThread(func, args=("thread2", self.output_log_signal, self.notify_signal))
self.workers["thread2"].start()
def output_log(self, msg):
self.logger.error(msg, self._ui.browser_log)
if __name__ == '__main__':
# 创建应用程序
app = QApplication(sys.argv)
logger = MyLogger("日志记录器")
win = MyWindow(logger, "测试可视化")
win.show()
# 进入消息循环
sys.exit(app.exec_())
注意: