python标准模块----logging

文章目录

  • Debug方式
  • logging日志级别
  • logging 的基本使用
  • logging的定制使用
  • 综合案例

Debug方式

  1. 通过print,逐行打印,找到问题;(还得逐行删除,麻烦)
  2. 通过logging模块,logging.debug(“xxx”)
  3. 设置断点,pycharm-debug
     

logging日志级别

  1. 日志级别
    debug < info < warning < error < critical

debug, 调试时用
info, 输出普通的信息(程序按照预期执行)
warning, 警告信息
error, 程序出现的一些错误
critical,程序无法执行的错误。
设置级别为info时,只会输出info及更高的级别的信息。

  1. 格式化参数
    %(asctime)s,格式化时间
    %(message)s,日志信息
    %(levelname)s,日志级别
    %(name)s,日志器名称
    %(pathname)s 输出日志的文件的绝对路径
    %(filename)s 输出日志的文件名
    %(lineno)s 输出日志的行号(在第几行)
    %(funcName)s 调用日志记录函数的函数名

logging 的基本使用

  1. 输出日志到控制台
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("输出日志到文件中")

 

logging的定制使用

步骤:

  1. 实例化一个日志记录器(Logger对象)
  2. 实例化一个日志处理器(Handler对象)
  3. 处理器添加日志级别&格式
  4. 日志记录器,添加日志处理器

案例:

# 实例化日志记录器
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("自定义日志记录器...")

一个日志记录器还可以添加多个日志处理器
 

综合案例

python标准模块----logging_第1张图片

如图,将日志内容输出到指定的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_())

注意:

  1. 实例对象访问类属性的Signal时,会创建一个新信号对象;
  2. QTextBrowser 先设置文本颜色,在追加文本,追加文本较多时,自动添加滚动条;
  3. record对象可以获取levelname(日志级别);
  4. 变量不能使用emit命名,会覆盖信号的emit方法。

你可能感兴趣的:(python基础,python,logging,builtin,日志案例)