如果你把跟踪代码放在另一个函数中,并从主代码调用该函数,则需要确保从祖父级获取堆栈信息,而不是父级或跟踪函数本身。
以下是一个三层深的系统示例,以进一步说明我的意思。我的主函数调用一个跟踪函数,该函数又调用另一个函数来执行工作。
import sys, os, inspect, time
time_start = 0.0
def trace_libary_init():
global time_start
time_start = time.time()
def trace_library_do(relative_frame, msg=""):
global time_start
time_now = time.time()
total_stack = inspect.stack()
total_depth = len(total_stack)
frameinfo = total_stack[relative_frame][0]
relative_depth = total_depth - relative_frame
func_name = frameinfo.f_code.co_name
filename = os.path.basename(frameinfo.f_code.co_filename)
line_number = frameinfo.f_lineno
func_firstlineno = frameinfo.f_code.co_firstlineno
fileline = "%s:%d" % (filename, line_number)
time_diff = time_now - time_start
print("%13.6f %-20s %-24s %s" % (time_diff, fileline, func_name, msg))
def trace_do(msg=""):
trace_library_do(1, "trace within interface function")
trace_library_do(2, msg)
def main(argc, argv):
rc=0
trace_libary_init()
for i in range(3):
trace_do("this is at step %i" %i)
time.sleep((i+1) * 0.1)
return rc
rc=main(sys.argv.__len__(), sys.argv)
sys.exit(rc)
这将会打印出类似于以下内容的结果:
$ python test.py
0.000005 test.py:39 trace_do trace within interface func
0.001231 test.py:49 main this is at step 0
0.101541 test.py:39 trace_do trace within interface func
0.101900 test.py:49 main this is at step 1
0.302469 test.py:39 trace_do trace within interface func
0.302828 test.py:49 main this is at step 2
顶部的trace_library_do()函数是一个示例,您可以将其放入库中,然后从其他跟踪函数中调用它。相对深度值控制打印哪个Python堆栈条目。
我在该函数中展示了一些其他有趣的值,比如函数起始行号、总堆栈深度和文件的完整路径。虽然我没有展示,但函数中的全局变量和本地变量也可以在inspect中使用,以及所有低于你的其他函数的完整堆栈跟踪。以上所示的信息已经足够生成分层调用/返回时间跟踪了。从这里开始创建自己源级别的调试器并不需要太多,而且大部分都已经准备好等待使用。
我相信会有人反对我使用inspect结构返回的数据内部字段,因为可能会有访问函数可以为您完成相同的事情。但我通过在Python调试器中步进此类型的代码来找到它们,并且它们至少在这里工作。我正在运行Python 2.7.12,如果您运行不同版本,则结果可能会有所不同。
无论如何,我强烈建议您将inspect代码导入自己的Python代码中,并查看它可以为您提供什么——特别是如果您可以在良好的Python调试器中单步执行代码。您将了解Python的工作原理,并看到语言的好处以及使其成为可能的背后发生的事情。
具有时间戳的完整源级跟踪是增强您对代码在动态实时环境中执行的理解的绝佳方式。这种类型的跟踪代码的好处在于,一旦编写完成,您就无需调试器支持即可查看它。
logging
模块并配置格式化程序:https://docs.python.org/2/library/logging.html#logrecord-attributes。Tornado Web 框架实际上具有非常类似的格式,因此您可以使用他们的代码:http://tornado.readthedocs.org/en/latest/_modules/tornado/log.html#LogFormatter - Blender