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模块进行日志记录的简单使用案例。最后,编写一个可以自行控制日志记录开关的类装饰器,来实现日志记录功能的动态扩充。
领取专属 10元无门槛券
私享最新 技术干货