【问题标题】:Twisted unhandled error扭曲的未处理错误
【发布时间】:2011-10-21 05:19:32
【问题描述】:

当扭曲反应器正在运行并且在未捕获的延迟中发生异常时,“未处理的错误”会与回溯和异常一起打印到终端。是否可以处理/拦截这些异常(例如,设置回调或覆盖方法)?

编辑:我知道我可以通过将 errback 添加到 deferrerd 来捕获失败。我想知道的是,是否有办法拦截一个未处理的故障/异常,该故障/异常已经沿着链向上遍历到反应器。

编辑:本质上,我想知道扭曲反应器是否具有全局错误处理程序或可以访问的东西。我想知道,因为它会打印失败的回溯和错误。

例子:

Unhandled Error
Traceback (most recent call last):
  File "/var/projects/python/server.py", line 359, in run_server
    return server.run()
  File "/var/projects/python/server.py", line 881, in run
    reactor.run()
  File "/usr/local/lib/python2.6/dist-packages/Twisted-11.0.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 1162, in run
    self.mainLoop()
  File "/usr/local/lib/python2.6/dist-packages/Twisted-11.0.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 1171, in mainLoop
    self.runUntilCurrent()
--- <exception caught here> ---
  File "/usr/local/lib/python2.6/dist-packages/Twisted-11.0.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 793, in runUntilCurrent
    call.func(*call.args, **call.kw)
  File "/var/projects/python/server.py", line 524, in monitor
    elapsed = time.time() - info.last
exceptions.NameError: global name 'info' is not defined

【问题讨论】:

  • 也许代码 sn-p 会比一般的回溯更有用。
  • 基本上,我想知道扭曲反应器是否有全局错误处理程序或可以访问的东西。我想知道,因为它会打印失败的回溯和错误。
  • 这是一个更明确的问题!我不这么认为,但让我看看...... ;-)

标签: python twisted reactor twisted.internet


【解决方案1】:

因为这些回溯是通过调用twisted.python.log.deferr()(无论如何在 Twisted 10.2 中)编写的,所以可以使用日志观察器重定向它们。这是与这些堆栈跟踪最常见的事情。我找不到日志观察者的任何基类(令人惊讶),但有几个内置:

twisted.python.log.PythonLoggingObserver - 记录的任何内容都会转到标准 Python logging 模块。 (我在我的应用程序中使用它。)

twisted.python.log.FileLogObserver - 记录的任何内容都会写入文件。

这两个都将捕获反应堆报告的堆栈跟踪。您所要做的就是构造日志观察器(无参数),然后调用对象的start() 方法。

(旁注:还有一个 StdioOnnaStick 类,您可以根据需要构造并分配给 sys.stdout 或 sys.stderr。然后您 print 的任何内容都会进入 Twisted 日志。)

要真正拦截这些调用,让堆栈跟踪永远不会被记录,您可以:

  • 子类twisted.internet.SelectReactor 并覆盖其runUntilCurrent() 方法。这就是记录堆栈跟踪的内容。在执行此操作之前,您需要研究 twisted.internet.base.ReactorBase 的来源。
  • 完成所有twisted.* 导入后,将twisted.python.log.deferr 设置为您选择的与原型def err(_stuff=None, _why=None, **kw) 兼容的函数。

【讨论】:

  • 所有好东西,除了你应该真的永远不要推荐子类化反应器。编写自己的反应器会使您远离 Twisted 的大量功能;任何涉及 GUI 或为您的平台优化的多路复用器(epoll、kqueue、IOCP)的东西,而且很少需要。另外,monkeypatching deferr 太激烈了。正确的做法是采纳您对日志观察者的建议。您可以自己编写并包装现有的观察者,您不需要子类化其中一个命名类。
  • 是的,这有点取决于他所说的“拦截”是什么意思。如果他的意思是“完全沉默”,那么希望为了实现这一点而不得不与 Twisted 内部人员混为一谈的前景会抑制它。我也推荐使用其中一个日志观察器类。
  • 谢谢。日志观察者应该可以工作。将反应堆子类化可能有点过头了,但很高兴知道。
【解决方案2】:

你可以给 deferred 添加一个 errback;未处理的异常会自动转换为twisted.python.failure.Failure。

【讨论】:

  • “failures”表示twisted.python.failure.Failure的实例
  • 我知道我可以通过将 errback 添加到 deferrerd 来捕获失败。我想知道的是,是否有一种方法可以拦截一个未处理的故障/异常,该故障/异常已经沿着链向上到达反应堆。
  • @C.P.Burns:由于异常转化为失败,如果在deferred中添加errback,则可以拦截。我错过了什么吗?
  • @GaretJax: C.P.似乎想知道如何对 所有 记录的异常执行此操作(无论它们是否来自 Deferred),而不知道它们可能来自哪个 Deferred。
  • @Glyph:对我来说,它似乎与延迟完全相关:“延迟中发生异常”;无论如何,我在 C.P. 之前写了这个答案。评论并编辑了他的问题。 ;-)
【解决方案3】:

回答您的评论:

本质上,我想知道扭曲反应器是否具有全局错误处理程序或可以访问的东西。我想知道,因为它会打印失败的回溯和错误。

响应是“不正确”。

首先,reactor与deferreds无关,实际上,整个deferred模块应该放在twisted.python包中,但是由于一些依赖关系,目前还不能这样做。回到你的问题...

深入了解扭曲的代码(更准确地说,twisted.internet.defer 模块),您可以概述以下事件流:

  1. 当调用callback 方法并返回结果时,延迟实例开始通过_runCallbacks 方法运行其回调;
  2. 如果其中一个回调抛出异常,则将其包装到失败中(542 行);
  3. 如果回调链耗尽且最后一个结果失败,则将当前结果分配给DebugInfo 实例的failResult 属性(575 行);
  4. 如果延迟实例及其DebugInfo 实例被垃圾回收,结果仍然存在活动故障,则调用DebugInfo.__del__ 方法并打印回溯。

鉴于这些前提,最简单的解决方案之一是猴子修补DebugInfo 类:

from twisted.internet.defer import DebugInfo
del DebugInfo.__del__  # Hides all errors

【讨论】:

  • 这是错误的 - 有几种方法可以通过添加日志观察器来拦截错误,这些日志观察器将捕获 Failure 对象并以各种方式处理它们。其他答案讨论了其中一些。不会投反对票,因为这是对代码的有趣探索,但请不要接受这个建议。
  • 不会和你争论……不会有机会的。 ;-) 但是如果你有几个日志观察者并且你想对他们隐藏它呢?如果我没记错的话,它们会被迭代调用,是吗?
  • 这不是一个非常有用的东西。如果您不希望观察者看到它,请不要发出错误(这相当于在这种特殊情况下添加正确的 errback)。
  • 我同意你的观点(这就是为什么我首先回答了另一个答案),但也许,不是隐藏错误,而是你想触发其他操作(但不记录它们)......答案中的猴子补丁代码只是可能的例子之一。请注意,我并不是说我的答案是正确的,我只是对此感到好奇。
  • 感谢 reactor 和 deferred 之间的澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-09
相关资源
最近更新 更多