断点调试和日志调试之间的平衡点 --- 函数计算调试之python篇

本文涉及的产品
函数计算FC,每月15万CU 3个月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介:

python 调试篇

很多初学者喜欢使用断点调试,方便之处是可以查到运行期各种栈内的变量值,来帮助debug。
但这一点如果脱离了IDE,其实是非常困难的。在服务器的执行过程中,更需要使用attach的方式才可能做到这点。

对于一些生产环境的错误定位,用断点调试几乎是完全不可能的。

而使用日志来做错误定位,对于一些脚本语言,尤其弱类型的语言,当你将一个变量经过多个函数传递的过程中,如果传递过程中不小心有拼写错误,只有最后使用到这个变量的地方才报出错误来,使用日志的方式要定位什么地方写错了非常困难,对于生产环境中多分支调用链极长的逻辑,更是难上加难。

本文将介绍一种结合函数堆栈,捕获栈中local变量的方式来达到快速定位bug的目的。

相对于其他runtime,python可以获取到很多运行时信息。通常来说,通过异常捕获,python 默认的traceback 给出的栈和错误信息已经能帮助开发者调试了。但时常来说,这并不是万能的,偶尔会遇到一些问题,必须加日志才能解决。但如果开发者日志加得不够细,生产环境中也很难立即重现,此时有什么好办法呢?

下面我们通过一个简单的例子来讲解如何在断点调试和日志调试中找一个平衡点定位python脚本中的bug。

def bar(c):
    x = [1,2,3,4]
    return x[c]

def foo(a, b):
    c = a + b
    bar(c)

def test():
    try:
        foo(2, 5)
    except:
        print "traceback"

假设 bar 中数组访问越界,实际的bug在c = a + b 那行,其实本应该是c = a - b,我们没有日志,此时如何定位到这个bug?

使用范例:

  • 我们先创建代码目录:
mkdir ~/sandbox/fc/traceback/python
  • 复制粘贴以下代码到 ~/sandbox/fc/traceback/python/main.py
import tracebackturbo as traceback

def bar(c):
    x = [1,2,3,4]
    return x[c]

def foo(a, b):
    c = a + b
    bar(c)

def handler(event, context):
    try:
        foo(5, 2)
    except:
        print traceback.format_exc(with_vars=True)

if __name__ == '__main__':
    handler(None, None)
  • 然后切换到 ~/sandbox/fc/traceback 目录
  • 执行 shell 命令: fcli shell,关于 fcli
  • 执行下述命令,其中 -d python 指的是当前代码所在目录 python ,而 python2.7python2.7 runtime
sbox -d python -t python2.7
pip install --target=$(pwd) tracebackturbo
  • 本地可以先做一下测试:
python main.py

测试结果:

Traceback Turbo (most recent call last):
  File "main.py", line 13, in test
    Local variables:
    foo(5, 2)
  File "main.py", line 9, in foo
    Local variables:
      a = 5
      b = 2
      c = 7
    bar(c)
  File "main.py", line 5, in bar
    Local variables:
      c = 7
      x = [1, 2, 3, 4]
    return x[c]
IndexError: list index out of range

我们可以看到栈中每个local变量都已经被print了出来,在生产环境中,我们可以在 service 上设置 logstore,将这部分错误信息输出到日志服务。

比较

我们可以比较全日志traceback 日志的优缺点:

  • 全日志

    • 优点

      • 可以隐藏敏感信息
      • 对于无报错,无异常抛出的代码也可以做有效记录
    • 缺点

      • 日志可能记录不全,线上问题调查很困难
      • 需要记录大量日志,太多的日志会导致性能低下
  • traceback 日志

    • 优点

      • 报错时可以拿到整个栈的信息,分析问题可以非常全面
      • 日志简洁,在没有报错的时候,不会有其他信息干扰
      • 由于只在报错才有日志,正常情况下只有try的开销,相对来说性能更高
    • 缺点

      • 局部变量中含有敏感信息,可能会暴露给日志查看人员

实现原理简介

接下来我们了解一下这个库的实现原理,简要提一下计算机系统运行时栈的结构:

栈结构

stack top
frame 0 (bar)
frame 1 (foo)
frame 2 (...)
...
frame n()

frame 的结构

name comment
function proto 函数信息地址
frame base frame 基地址
args 函数参数地址
ret 函数返回地址
var1 第一个局部变量的空间
var2 第二个局部变量的空间
... ...
varN 第N个局部变量空间

通常来说,各类计算机语言的 runtime 实现(实现细节及名称可能各不相同)都会包含上述信息。

function proto 结构

name comment
filename 实现文件名
line start, end 函数实现具体行
local variables 局部变量信息

每个变量包含

  • 声明行
  • 相对于frame 基地址偏移
  • 局部变量声明周期对应指令集

对于任何一个未 return 的函数,如果我们拿到了这个栈,就可以获取到栈顶的若干 frame ,找到function proto,就可以找到各个局部变量的偏移,通过 frame 基地址相加,我们就可以得到每个局部变量的地址,获取到每个变量的内容。

相关链接

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
10天前
|
存储 JSON 监控
告别Print,使用IceCream进行高效的Python调试
本文将介绍**IceCream**库,这个专门用于调试的工具显著提升了调试效率,使整个过程更加系统化和规范化。
32 2
告别Print,使用IceCream进行高效的Python调试
|
1月前
|
Java 程序员 应用服务中间件
「测试线排查的一些经验-中篇」&& 调试日志实战
「测试线排查的一些经验-中篇」&& 调试日志实战
22 1
「测试线排查的一些经验-中篇」&& 调试日志实战
|
28天前
|
Python
python读写操作excel日志
主要是读写操作,创建表格
56 2
|
27天前
|
Python Windows
python知识点100篇系列(24)- 简单强大的日志记录器loguru
【10月更文挑战第11天】Loguru 是一个功能强大的日志记录库,支持日志滚动、压缩、定时删除、高亮和告警等功能。安装简单,使用方便,可通过 `pip install loguru` 快速安装。支持将日志输出到终端或文件,并提供丰富的配置选项,如按时间或大小滚动日志、压缩日志文件等。还支持与邮件通知模块结合,实现邮件告警功能。
python知识点100篇系列(24)- 简单强大的日志记录器loguru
|
1月前
|
数据采集 机器学习/深度学习 存储
使用 Python 清洗日志数据
使用 Python 清洗日志数据
36 2
|
2月前
|
消息中间件 Kafka API
python之kafka日志
python之kafka日志
32 3
|
2月前
|
Python
5-9|Python获取日志
5-9|Python获取日志
|
2月前
|
开发者 Python
基于Python的日志管理与最佳实践
日志是开发和调试过程中的重要工具,然而,如何高效地管理和利用日志常常被忽略。本文通过Python中的logging模块,探讨如何使用日志来进行调试、分析与问题排查,并提出了一些实际应用中的优化建议和最佳实践。
|
2月前
|
监控 Python Windows
python知识点100篇系列-pysnooper用于调试
PySnooper是一个便捷的Python调试工具,用于监控代码执行过程及局部变量的变化,替代繁琐的打印语句。作为GitHub上的热门开源项目,它通过装饰器自动记录代码执行细节。安装简便,支持多种平台,可通过pip安装。使用时,只需在目标函数上添加装饰器即可实时查看变量变化或将其记录至日志文件。此外,还支持使用with块对特定代码段进行调试。更多详细信息可参阅其官方使用文档。
python知识点100篇系列-pysnooper用于调试
|
2月前
|
Python
Python如何将日志输入到文件里
Python如何将日志输入到文件里

热门文章

最新文章

相关产品

  • 函数计算