python插装--sys.settrace

简单来说最近在做回归测试的相关工作→

回归测试需要根据版本之间代码的变更选择测试用例→

尝试静态和动态生成调用图方法后选择用动态生成方法解决→

选用第三方库pycallgraph魔改了一部分算是满足了跑实验的需求→

跑的差不多了想搞清楚内部具体怎么实现插装→

有了本文

看过部分源码后发现使用了sys.settrace进行插桩跟踪运行时的轨迹,不知怎么发现SO上的这个问题

2019-03-28 20-40-01屏幕截图.png

项目开发者在13年就实现这玩意儿了,虽然这个项目在15年就已经没继续更新,但是依然能比较好的兼容最新的python版本(大概是用到的built-in lib没啥大变化)。

跟踪函数需要接收三个参数framehttps://docs.python.org/3/library/sys.html#sys.settrace ),eventhttps://docs.python.org/3/reference/datamodel.html#types ),arghttps://docs.python.org/3/library/sys.html#sys.settrace )。其中arg的值与event类型有关。

通过内省inspect可获得代码的模块信息,包括模块路径和模块名,跟踪前设置sys.settrace(tracer)进行跟踪,sys.settrace(None)关闭跟踪,frame.f_locals可以获取调用函数时参数的信息,具体更多属性可以在frame后的链接中查找。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import sys
from main import add
import inspect


class Tracer:

def dump(self, frame, event, arg):
code = frame.f_code
module = inspect.getmodule(code)
module_name = ""
module_path = ""
if module:
module_path = module.__file__
module_name = module.__name__
print(event, module_path, module_name, code.co_name, frame.f_lineno, frame.f_locals, arg)

def trace(self, frame, event, arg):
self.dump(frame, event, arg)
return self.trace

def collect(self, func, *args):
sys.settrace(self.trace)
func(*args)
sys.settrace(None)


if __name__ == "__main__":
t = Tracer()
t.collect(add, 1, 2)

然后给了一个demo,让我们写的tracer跟踪它的执行。

1
2
3
4
5
6
7
8
9
def add(a, b):
c = 3
d = 4
e = c + d
return a + b + e


if __name__ == "__main__":
print(add(1, 2))

运行结果:

2019-03-28 21-00-31屏幕截图.png

完。