首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

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

1

引言

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

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

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

2、日志记录的内置模块

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

2

关于日志的基本认知

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

日志的核心组成部分有:

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

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

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

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

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

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

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

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

3

日志记录的内置模块

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

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

直接看代码:

import loggingimport 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)

执行结果:

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

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

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

4

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

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

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

直接看代码:

import loggingimport 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')

@loggerdef 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)

执行结果:

5

总结

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

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OX-hPJZJGT0Q9uxa7lomO8aA0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券