封装logging模块

本文详细介绍了如何封装Python的logging模块,包括简单封装和继承logging.Logger类进行封装。简单封装会导致行号和文件名显示错误,而通过继承可以解决此问题,确保日志信息准确反映调用源代码的位置。示例代码展示了如何创建自定义的日志处理器,并在test.py中使用这些封装后的日志功能。
摘要由CSDN通过智能技术生成

上篇文章,简要介绍了 Python中的logging日志模块

简单封装

logging日志功能,可以将其封装成一个独立的模块,这样,在需要使用到日志功能的地方,导入这个模块即可以使用

my_logger.py

import logging

class LoggerHandler():

    # 初始化 Logger
    def __init__(self,
                 name='root',
                 logger_level= 'DEBUG',
                 file=None,
                 logger_format = '%(asctime)s-%(message)s'
                 # logger_format = '%(asctime)s-%(filename)s-%(lineno)d-%(message)s'
                 ):

        # 1、初始化logger收集器
        logger = logging.getLogger(name)


        # 2、设置日志收集器level级别
        logger.setLevel(logger_level)

        # 5、初始化 handler 格式
        fmt = logging.Formatter(logger_format)

        # 3、初始化日志处理器

        # 如果传递了文件,就会输出到file文件中
        if file:
            file_handler = logging.FileHandler(file)
            # 4、设置 file_handler 级别
            file_handler.setLevel(logger_level)
            # 6、设置handler格式
            file_handler.setFormatter(fmt)
            # 7、添加handler
            logger.addHandler(file_handler)

        # 默认都输出到控制台
        stream_handler = logging.StreamHandler()
        # 4、设置 stream_handler 级别
        stream_handler.setLevel(logger_level)
        # 6、设置handler格式
        stream_handler.setFormatter(fmt)
        # 7、添加handler
        logger.addHandler(stream_handler)

        # 设置成实例属性
        self.logger = logger

    # 返回日志信息

    def debug(self,msg):
        return self.logger.debug(msg)

    def info(self,msg):
        return self.logger.info(msg)

    def warning(self,msg):
        return self.logger.warning(msg)

    def error(self,msg):
        return self.logger.error(msg)

    def critical(self,msg):
        return self.logger.critical(msg)

这样,需要用到日志的时候,通过导入 my_logger 模块,使用 LoggerHandler 类里的 debuginfo函数即可
这种封装方式,相当于重写了一个日志模块的功能

然而,如果将init里的内容,换成logger_format = '%(asctime)s-%(filename)s-%(lineno)d-%(message)s'
这种封装,会出现一些小问题,行号和文件会显示错误

新建立一个 test.py 文件
test.py

import my_logger

if __name__ == '__main__':
    logger = my_logger.LoggerHandler()
    logger.info('hello world!')

执行这个文件,打印的内容为:2021-08-29 21:12:25,462-my_logger.py-53-hello world!,这里的行号为 53,日志里的文件名称为my_logger.py
也就是说,打印的文件和行号,是封装的内容里的,而不是我们执行的 test.py 文件里的内容

这个问题出在了 1、初始化logger收集器 logger = logging.getLogger(name) 这一步
test.py 文件里调用的是LoggerHandler类的内容,logger初始化的时候,就已经把日志信息保存起来了,所以,调用 info 函数的时候, return self.logger.info(msg) 返回的是LoggerHandler类的info 函数 logger 的内容

继承 logging 模块进行封装

如果要解决这个问题,就不要像上面一样,重写日志模块的功能,而是要采用继承 logging 模块的方式,去封装日志模块

logging 模块中有一个 Logger 类,所以,在定义类的时候,需要继承这个 Logger 类

按住Ctrl,点击 logger = logging.getLogger(name)中的 getLogger,查看getLogger方法的内容

def getLogger(name=None):
    """
    Return a logger with the specified name, creating it if necessary.

    If no name is specified, return the root logger.
    """
    if name:
        return Logger.manager.getLogger(name)
    else:
        return root

备注的内容为:返回具有指定名称的日志收集器,并在必要时创建它。如果没有指定名称,则返回根日志收集器。
从备注中可以得知,这个函数的作用,是返回logger收集器。

按住Ctrl,点击 manager.getLogger(name) 中的 getLogger
里面有这样一行代码: rv = (self.loggerClass or _loggerClass)(name)
这行代码的作用,其实就是实例化一个类(日志Logger的类)。

所以,上面的问题,1、初始化logger收集器 logger = logging.getLogger(name) 这一步,实例化的是LoggerHandler类,在 test.py 文件里打印的日志内容,返回的是LoggerHandler类的info 函数 logger 的行号和文件名称

而采用继承的方式,继承logging 模块Logger 类,就不会出现这个问题了,因为调用的是logging 模块Logger 类,打印的日志内容,调用的的是logging 模块info 函数了,返回的行号和文件名称,就是正确的

所以,就不需要1、初始化logger收集器 logger = logging.getLogger(name) 这一步了,直接super().__init__(name)继承logging 模块Logger 类,将相应的内容,替换成 self就行了,也不需要再自定义 debuginfo这些方法了

my_logger2.py

import logging

class LoggerHandler(logging.Logger):

    # 初始化 Logger
    def __init__(self,
                 name='root',
                 logger_level= 'DEBUG',
                 file=None,
                 logger_format = " [%(asctime)s]  %(levelname)s %(filename)s [ line:%(lineno)d ] %(message)s"
                 ):

        # 1、设置logger收集器,继承logging.Logger
        super().__init__(name)


        # 2、设置日志收集器level级别
        self.setLevel(logger_level)

        # 5、设置 handler 格式
        fmt = logging.Formatter(logger_format)

        # 3、设置日志处理器

        # 如果传递了文件,就会输出到file文件中
        if file:
            file_handler = logging.FileHandler(file)
            # 4、设置 file_handler 级别
            file_handler.setLevel(logger_level)
            # 6、设置handler格式
            file_handler.setFormatter(fmt)
            # 7、添加handler
            self.addHandler(file_handler)

        # 默认都输出到控制台
        stream_handler = logging.StreamHandler()
        # 4、设置 stream_handler 级别
        stream_handler.setLevel(logger_level)
        # 6、设置handler格式
        stream_handler.setFormatter(fmt)
        # 7、添加handler
        self.addHandler(stream_handler)

test.py

import my_logger2

if __name__ == '__main__':
	curTime = time.strftime("%Y-%m-%d %H_%M", time.localtime())
	base_dir = os.path.split(os.path.abspath(__file__))[0]
	# 日志文件
    file_path = os.path.join(base_dir , '{}_test.log'.format(curTime))
    logger = my_logger2.LoggerHandler(file=file_path)
    logger.info('hello world!')

执行 test.py 文件 ,可以发现,打印的日志信息为:
[2021-08-29 22:47:33,124] INFO mytest.py [ line:5 ] hello world!,这个就正确了
当前py文件目录下还生成了一个log日志文件,日志文件里的内容与打印的内容一致

如果还想在日志中看到对应模块中的函数名称,可以再加上 funcName
即:logger_format = " [%(asctime)s] %(levelname)s [%(filename)s %(funcName)s] [ line:%(lineno)d ] %(message)s"

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Pythonlogging模块可以用来记录程序运行时的日志信息,包括调试信息、警告信息、错误信息等。为了方便使用,可以对logging模块进行封装,使其更容易调用和管理。 以下是一些可能有用的封装方法: 1. 封装基本配置:将logging模块的基本配置封装成一个函数,可以方便地进行调用和修改。例如: ```python import logging def init_logger(log_file): logger = logging.getLogger() logger.setLevel(logging.DEBUG) handler = logging.FileHandler(log_file) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) ``` 这个函数会初始化一个logger对象,并将其级别设置为DEBUG,将日志输出到指定的文件中,并使用指定的格式进行格式化。 2. 封装消息类型:可以定义不同的消息类型,例如debug、info、warning、error等,然后为每种类型都定义一个封装函数,以简化调用。例如: ```python import logging logger = logging.getLogger() def debug(msg): logger.debug(msg) def info(msg): logger.info(msg) def warning(msg): logger.warning(msg) def error(msg): logger.error(msg) ``` 这样,使用时可以直接调用对应的函数,例如: ```python debug('this is a debug message') warning('this is a warning message') ``` 3. 封装上下文信息:有时候需要在日志中添加一些上下文信息,例如当前时间、请求参数、用户ID等。可以定义一个上下文管理器,用with语句来管理上下文信息的输出。例如: ```python import logging logger = logging.getLogger() class LogContext: def __init__(self, **kwargs): self.kwargs = kwargs def __enter__(self): logger.info('start context', extra=self.kwargs) def __exit__(self, exc_type, exc_value, traceback): logger.info('end context', extra=self.kwargs) ``` 使用时可以这样调用: ```python with LogContext(user_id=123): logger.info('do something') ``` 这样会在日志中输出一条包含上下文信息的记录。 总之,封装logging模块可以帮助我们更方便地使用日志功能,提高开发效率和代码可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值