django - 如何查看渠道消费者引发的异常
问题描述
我开始使用django-channels
,我觉得它很棒。然而调试消费者是痛苦的,因为当从消费者内部引发一些异常时,终端不会打印任何内容,websocket 只是断开连接。
未显示的异常类型不明显识别。它是系统的情况AssertionError
,还有其他一些情况,例如下面的代码:
class MexicoProgressConsumer(ProgressConsumer):
def init(self, SSDBConfig, Sub_application):
subappli = models.Sub_application.objects.get(pk=Sub_application)
...
使用错误数量的参数调用此方法不会在控制台上打印任何内容并断开 websocket。get
如果最后一行的 失败,则同上。
有没有办法将这些异常视为其他异常?
解决方案
从 albar 的回答开始,我达到的解决方案是像这样定义一个装饰器
from functools import wraps
from logging import getLogger
from channels.exceptions import AcceptConnection, DenyConnection, StopConsumer
logger = getLogger("foo-logger")
def log_exceptions(f):
@wraps(f)
async def wrapper(*args, **kwargs):
try:
return await f(*args, **kwargs)
except (AcceptConnection, DenyConnection, StopConsumer):
raise
except Exception as exception:
if not getattr(exception, "logged_by_wrapper", False):
logger.error(
"Unhandled exception occurred in {}:".format(f.__qualname__),
exc_info=exception,
)
setattr(exception, "logged_by_wrapper", True)
raise
return wrapper
这有几个改进:
- 使用 functools.wraps 使包装的函数更接近原始函数。
- 使用 async/await 语法,因为我使用的是异步消费者(如果不是,请删除)
- 不记录 django-channels 故意引发的几个异常。
- 仅在没有
logged_by_wrapper
设置属性时记录异常。这导致异常只记录一次,因为我们在第一次记录后设置了属性。 - 使用 python 的内置
logging
模块来记录错误。这会自动格式化异常和回溯,因为我们在exc_info=exception
.
然后我定义了一个类装饰器而不是基类,以将其应用于消费者的方法
from inspect import iscoroutinefunction
def log_consumer_exceptions(klass):
for method_name, method in list(klass.__dict__.items()):
if iscoroutinefunction(method):
setattr(klass, method_name, log_exceptions(method))
return klass
这适用log_exceptions
于 Consumer 中定义的所有异步方法,但不适用于它继承的方法 - 即仅适用于 Consumer 的自定义方法。
推荐阅读
- python - 无法将关键字“is_active”解析为字段?选项有:active、admin、email、full_name、id 等
- c++ - C++ 模板类运算符重载
- javascript - 尝试创建一个 Javascript Tic Tac Toe
- qt - QQmlApplicationEngine 加载组件失败
- flutter - 使用 Flutter sqflite 返回单个字符串
- mysql - 如何创建一个表,其中包含一堆没有合并的其他表?
- c++ - 如何解决这个错误:Public 没有命名类型?
- c# - 如何在 protobuf-net.grpc 的消息中使用 IAsyncEnumerable?
- single-page-application - 使用 MSAL 进行 SPA 的多个用户会话
- swiftui - 在 ObservableObject 中引用 EnvironmentObject