引言
从系统开发的规范性来说,日志的记录是一个规范化的要求,但是,有些程序员会觉得麻烦,反而不愿意记录日志,还是太年轻了……
其实,如果个人保护意识稍微强一些,一定会主动进行日志的记录的,无论是后续的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)
执行结果:
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)
执行结果:
总结
本文简单介绍了日志的主要组成部分,以及日志记录的重要性。简单介绍了Python中利用logging模块进行日志记录的简单使用案例。最后,编写一个可以自行控制日志记录开关的类装饰器,来实现日志记录功能的动态扩充。
感谢您的拨冗阅读,希望对您有所帮助。