65、Python之函数高级:装饰器实战,通用日志记录功能的动态添加

引言

从系统开发的规范性来说,日志的记录是一个规范化的要求,但是,有些程序员会觉得麻烦,反而不愿意记录日志,还是太年轻了……

其实,如果个人保护意识稍微强一些,一定会主动进行日志的记录的,无论是后续的BUG追踪、定位,或者与用户的掰扯(这种情况更多,用户非说自己做了什么,其实可能没有做什么,最后赖系统有问题)。

从规范性和自我保护来看,我们都很有必要记录日志,问题点在于怎么让日志记录变得更加灵活、方便。本文继续聊聊装饰器在日志记录上的实战应用,从而更加便捷地实现日志的记录。

本文的主要内容

1、关于日志的基本认知

2、日志记录的内置模块

3、装饰器实现灵活的日志记录

关于日志的基本认知

日志(Log)是应用程序在运行过程中生成的一系列记录,这些记录可以描述系统当时的状态、行为、事件及可能的错误等。日志中通常会包含时间戳、日志级别、消息内容、以及相关上下文信息。日志可以输出到控制台、写入文件、写入数据库或者推送到远程服务等。

日志的核心组成部分有:

1、时间戳(timestamp):记录事件的发生时间,很多时候定位问题,都是基于时间戳首先进行日志的检索。

2、日志级别(Log Level):标识日志所记录事件的严重程度,一般分为:DEBUG、INFO、WARNING、ERROR、CRITICAL等。

3、消息内容(Message Content):用于描述事件内容的信息,用于辅助定位事件类型、原因等。

4、上下文信息(Context Information):通常会记录所属模块、函数、参数等额外信息,便于帮助定位问题。

关于日志的作用,主要有以下几点:

1、便于开发过程中的调试、问题定位等。

2、用于监控系统的健康状态和性能指标。

3、出于审计和合规的需要,保持业务的连续性。

4、用户行为分析,比如运营侧提出的数据埋点的需要。

5、交流和沟通:模块与模块之间的协作,以及掰扯的需要。

日志记录的内置模块

接下来,我们看一下在Python中进行日志记录的最基本的做法。

在Python中,我们可以通过logging模块来进行日志的记录。使用起来比较简单,这里我们以实际代码演示该模块的使用。

直接看代码:

import logging
import time

logger = logging.getLogger('__name__')
logger.setLevel(logging.INFO)
logger.addHandler(logging.FileHandler('./log.txt'))


def divide(a, b):
    logger.info(f'{time.strftime("%x %X", time.localtime())} 函数{divide.__name__}被调用 参数: {a},{b}')
    try:
        res = a / b
        logger.info(f'{time.strftime("%x %X", time.localtime())} 函数{divide.__name__}被调用 返回值: {res}')
    except Exception as e:
        # 参数exc_info表示记录异常信息
        logger.error(f'{time.strftime("%x %X", time.localtime())} 函数{divide.__name__}被调用 发生异常: {e}', exc_info=True)


if __name__ == '__main__':
    divide(10, 2)
    time.sleep(3)
    divide(10, 0)

执行结果:

2a1973dc32b7d52631639f8b5d7b3fe8.jpeg

logging模块的使用比较简单,需要注意的是:

1、首先需要获取一个日志记录对象,并通过setLevel()设置其记录的日志级别,按照重要程度,>=设置级别的日志都会被记录,但是<设置级别的日志不会被记录。比如,logger.setLevel(logging.INFO),则DEBUG级别的日志是不会被记录的。

2、当需要记录异常的详细信息,比如调用栈信息,则在记录日志时,需要设置exc_info=True。

其他的内容就不展开了,感兴趣的同学可以自行查阅相关文档。

装饰器实现灵活的日志记录

如果每个函数内部都要写一遍日志处理的代码,似乎有些繁琐。涉及到通用功能的动态添加,我们很自然地就会想到装饰器。

接下来,我们通过装饰器来实现日志的统一处理。这次,我们通过类装饰器来实现,同时实现日志记录灵活的打开与关闭功能。

直接看代码:

import logging
import time


class Logger:
    def __init__(self, log_path, is_enable=True):
        self.logger = logging.getLogger(log_path)
        self.logger.addHandler(logging.FileHandler(log_path))
        self.logger.setLevel(logging.INFO)
        self.is_enable = is_enable

    def enable(self, is_enable):
        self.is_enable = is_enable

    @staticmethod
    def get_time_str():
        return time.strftime("%x %X", time.localtime())

    def __call__(self, func):
        def wrap(*args, **kwargs):
            if self.is_enable:
                self.logger.info(f'{self.get_time_str()} 函数{func.__name__}被调用 参数: {args},{kwargs}')
            try:
                res = func(*args, **kwargs)
                if self.is_enable:
                    self.logger.info(f'{self.get_time_str()} 函数{func.__name__}被调用 返回值: {res}')
                return res
            except Exception as e:
                if self.is_enable:
                    self.logger.error(f'{self.get_time_str()} 函数{func.__name__}被调用 发生异常: {e}', exc_info=True)

        return wrap


logger = Logger('./log.txt')


@logger
def divide(a, b):
    return a / b


if __name__ == '__main__':
    divide(10, 2)
    time.sleep(3)
    divide(10, 0)
    logger.enable(False)
    divide(10, 3)
    logger.enable(True)
    divide(5, 2)

执行结果:

8b4e06794a81d2abce157fc4eb932e64.jpeg

总结

本文简单介绍了日志的主要组成部分,以及日志记录的重要性。简单介绍了Python中利用logging模块进行日志记录的简单使用案例。最后,编写一个可以自行控制日志记录开关的类装饰器,来实现日志记录功能的动态扩充。

感谢您的拨冗阅读,希望对您有所帮助。

7ed0ad29272a99e4b6a7276480c8d217.jpeg

  • 21
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南宫理的日知录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值