如何跟踪现有python扭曲应用程序的执行情况

时间:2014-05-20 12:28:47

标签: python debugging refactoring twisted

所以...很可能很多人会从你的职业生涯中认识到这一点。

你已经继承了数百个文件的代码库,数千行,每行包含对象,闭包和全局变量,没有单元测试,而且很多文件实际上可能是死代码,从来没有被称为任何文件更多。一个人(他是一个超级聪明的家伙,但是一个完整的黑客)写了大部分内容(就像所有的一样)并且他已经不在了。有趣的python怪癖比比皆是,它们做了所需的事情,但没有评论来说明他们为什么会在那里。

d = dict(d)

其中d已经是一个字典(传递给方法),到目前为止我个人最喜欢...(浅层复制有一个原因 - 花了我一段时间来解决这个问题)不同路径使用的通用方法

,系统并知道他们需要做什么
if <passed_in_param>["XXX"] = <something>:
    <pathA>
    return A
elif <passed_in_param>["ZZZ"] = <somethingElse>:
    <pathB>
    return B

这是......等......等等 - 只是通常会被重构的东西。

我真正的问题是,在我真正开始调试它之前,我需要了解应用程序的工作方式......再次 - 对于很多人来说,熟悉的领域我确定。

系统使用twisted来托管一堆http端点(使用twistd),并且有大量端点占用各种根。每一个都有趣的&#39;事实上,但基本上它们都与各种数据库或第三方休息端点进行通信,然后聚合某些格式的东西并返回休息响应。 Twisted是一个非常好的框架!

现在,有什么方法可以让扭曲的框架帮我开始调试吗?像设置一些标志一样简单,这样无论何时触发回调 - 它都会打印传递给回调的方法和参数?这不是我在文档中找到的东西。

你们做什么?任何提示和答案都会受到欢迎。

如果我有的话,我不会在我当地的开发盒上扭曲猴子。

更新 - 一些hacky进展............ 我自己并没有超越一些hackyness,我提出了一些比没有更好的东西。

在tap.py文件中,扭曲的启动器启动我已经把它(如果其他人发现这个有用):

trace_exclusions = ["twisted", "DQL2SQL", "DDBClient", "exon_parser", "ontology", "pglib"]

def tracefunc(frame, event, arg, indent=[0]):
    if frame.f_code.co_filename.startswith("<!redacted!>/src/"):
        if not any(te in frame.f_code.co_filename for te in trace_exclusions):
            if event == "call":
                indent[0] += 2
                print "-" * indent[0], frame.f_code.co_filename.replace("/<!redacted!>/src/", ""), frame.f_code.co_name, frame.f_code.co_varnames
            if event == "return":
                indent[0] -= 2
    return tracefunc

import sys
sys.settrace(tracefunc)

我得到了一些有用的输出:

-- servers/http/base.py getResourceFor ('self', 'request', 'path', 'full_path', 'channel', 'category', 'service', 'version', 'market', 'locale', 'currency', 'query_id', 'extra_id')
-- servers/carhire_api/carhire_api.py render_GET ('self', 'request', 'entity_id', 'distance', 'dql', 'd', 'response')
---- servers/carhire_api/carhire_api.py get_int_parameter ('request', 'param_key')
---- servers/carhire_api/carhire_api.py get_int_parameter ('request', 'param_key')
---- beautify/deferred_entity_beautify.py get_entity_id ('pkid', 'val', 'iface', 'd')
------ cache/apc_cache.py __getitem__ ('self', 'key')
------ beautify/deferred_entity_beautify.py get_interface_id ()
------ kraken/client.py get ('self', 'key', 'd')
-------- kraken/client.py _get_multi ('self', 'connection', 'keys', 'task', 'd')
---------- kraken/twist.py get ('self', 'namespace', 'keys', 'task', 'the_size', 'req', 'r', 'the_timeout', 'l', 'idx', 'tmp_keys', 'd_l', 'exc')
------------ kraken/__init__.py get ('self', 'namespace', 'keys', 'req')
-------------- kraken/__init__.py request ('self', 'method', 'namespace', 'data', 'req')
---------------- kraken/__init__.py <genexpr> ('.0', 'x')
---------------- kraken/__init__.py <genexpr> ('.0', 'x')

但如果有人有更好的事情 - 我知道!

2 个答案:

答案 0 :(得分:3)

已开始使用工具开展一些工作,尤其是Deferred更容易调试。 https://twistedmatrix.com/trac/ticket/1402上有一些信息,https://twistedmatrix.com/trac/ticket/4304引用的分支中有一些代码。这些工具实际上并不是Twisted的一部分,所以尝试使用它们有点不方便。在最坏的情况下,也许他们会给你一些想法,也许你真的会在你的应用程序中找到一种方法来使用它们。

与您已编写的基于跟踪钩子的示踪剂类似,有twisted.python.util.spewerepsilon.spewer.Spewer。但是,这些可能实际上不会提供比您已经构建的工具更多的信息。

答案 1 :(得分:0)

在原始帖子中添加此内容已足够长。除了Jean-Paul所说的那篇文章之外 - 我在tap.py中编写了一个启动应用程序的黑客。我会在这里发布,以防将来对任何人都有用。它确实为我提供了我需要的信息 - 当我点击一个端点时会发生什么......显然,将这​​个与原始延迟链相关联的事情会更加令人敬畏。我从Jean-Paul发布的链接中获取了一些代码 - 谢谢。

trace_exclusions = [
    "twisted",
    "DQL2SQL",
    "DDBClient",
    "exon_parser",
    "ontology",
    "pglib",
    "servers/interfaces/counter.py",
    "event_feed/feed_register.py",
    "database_notification_manager",
    "revenue_optimization"
    ]

def extractArgs(frame):
    co = frame.f_code
    dict = frame.f_locals
    n = co.co_argcount
    if co.co_flags & 4: n = n+1
    if co.co_flags & 8: n = n+1
    result = {}
    for i in range(n):
        name = co.co_varnames[i]
        if name != "self":
            r = dict.get(name, "----")
            r = str(r)
            if len(r) > 30:
                r = r[0:28] + '..'
            result[name] = r 
    return result

def tracefunc(frame, event, arg, indent=[0]):
    if frame.f_code.co_filename.startswith("/home/developer/projects/befogg/servers/nlp/src/"):
        if not any(te in frame.f_code.co_filename for te in trace_exclusions):
            if event == "call":
                indent[0] += 1
                print "-" * indent[0], frame.f_code.co_filename.replace("/home/developer/projects/befogg/servers/nlp/src/", ""), frame.f_code.co_name, "VARS:", frame.f_code.co_varnames
                print "-" * indent[0], frame.f_code.co_filename.replace("/home/developer/projects/befogg/servers/nlp/src/", ""), frame.f_code.co_name, "ARGS:", extractArgs(frame)
            if event == "return":
                indent[0] -= 1
    return tracefunc

import sys
sys.settrace(tracefunc)