协程gevent记录错误日志堆栈信息

原因

  • 实际工作中遇到的问题,使用gevent协程来提高性能,但发现携程中的异常堆栈信息抓取不到

第一次尝试

try:
	result = {}
    gevent.joinall([
        gevent.spawn(self.desktop_statistics_info, result),
        gevent.spawn(self.user_statistics_info, result),
        gevent.spawn(self.client_statistics_info, result),
        gevent.spawn(self.iaas_statistics_info, result),
        gevent.spawn(self.desktop_attach_user_statistics_info, result)
    ])
except Exception as e:
	# 异常信息被囚禁,不会走到此处
    logger.error(traceback.format_exc())
  • 问题:使用try\exception来捕获,然后使用traceback模块来记录错误堆栈信息,发现在我的项目中gevent.joinall不会将异常抛出来,查阅资料发现,携程会在内部消化整个异常信息,不会对外暴露,提示我们可以在外部判断exception抓取
    在这里插入图片描述

第二次尝试

tasks = gevent.joinall([
    gevent.spawn(self.desktop_statistics_info, result),
    gevent.spawn(self.user_statistics_info, result),
    gevent.spawn(self.client_statistics_info, result),
    gevent.spawn(self.iaas_statistics_info, result),
    gevent.spawn(self.desktop_attach_user_statistics_info, result)
])
for task in tasks:
    if task.exception:
    	logger.error(task.exception)
  • 问题:task.exception仅包含了错误的内容,并未包含整个错误的堆栈信息,因此该日志记录对于解决bug没有太大帮助,所以我需要找到整个异常堆栈信息,并记录日志。通过对task对象打断点,发现task内部包含了exc_info这个错误对象,其实就是sys.exc_info(),会记录整个异常堆栈,该对象不做分析,不了解的自行查询。接下来的工作就是如何从sys.exc_info()提取到有效的堆栈信息,并记录日志。在网上找了一圈没找到,只能自行摸索。

第三次尝试

result = {}
tasks = gevent.joinall([
    gevent.spawn(self.desktop_statistics_info, result),
    gevent.spawn(self.user_statistics_info, result),
    gevent.spawn(self.client_statistics_info, result),
    gevent.spawn(self.iaas_statistics_info, result),
    gevent.spawn(self.desktop_attach_user_statistics_info, result)
])
for task in tasks:
    if task.exception:
    	with open("xxxxx/xxxxx/xxx/log", "a") as log:
    		traceback.print_exception(*task.exc_info, file=log)
  • 首先查看了traceback源码,发现有一个print_exception的方法,支持传递三个参数etype, value, tb,正好是sys.exc_info()返回的元组,直接掉用traceback.print_exception(*task.exc_info),发现完美的在控制台输出了错误的堆栈信息,但是print_exception以看就是只能输出在控制台,我们要如何输出到日志文件中呢?
  • 在次进入到print_exception方法中,发现该方法还支持一个file的参数,开始以为直接传递一个文件路径即可,看到报错信息后发现file接受的是一个文件对象,即:with open("xxx", "a") as f:,此处为何使用a打开文件,每个人需求不一样,自己思考。传递项目日志文件对象后发现,错误堆栈信息被完美的记录进去了,至此需求已经得到解决。
  • 由于项目的日志文件路径是动态生成的,所以此处直接将路径写死,不便于后期的维护,所以只能硬着头皮往下继续看print_exception内部是如何将错误堆栈信息获取以及写入指定的文件的,只要找到exc_info怎么解析的,写入文件不就so easy

最后一次尝试

def exc_info_logger(exc_type, exc_value, exc_tb, errmsg=""):
    """主要用来记录gevent错误堆栈信息"""
    err_info = errmsg + "\n"
    for line in traceback.TracebackException(exc_type, exc_value, exc_tb).format(chain=True):
        err_info += line
    logger.error(err_info)
result = {}
tasks = gevent.joinall([
    gevent.spawn(self.desktop_statistics_info, result),
    gevent.spawn(self.user_statistics_info, result),
    gevent.spawn(self.client_statistics_info, result),
    gevent.spawn(self.iaas_statistics_info, result),
    gevent.spawn(self.desktop_attach_user_statistics_info, result)
])
for task in tasks:
    if task.exception:
    	exc_info_logger(*task.exc_info, errmsg="Data statistics interface abnormal")
  • 通过看print_exception源码,发现其解析exc_info主要用到了TracebackException这个类,这就简单了,我们直接导入该TracebackException类,来解析我们从gevent中获取到的exc_info即可,然后将解析的错误堆栈信息写入我们的日志文件就完美了。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值