Add convenience method for exception reporting (#2792)
This commit is contained in:
52
sanic/app.py
52
sanic/app.py
@@ -17,7 +17,7 @@ from asyncio import (
|
||||
from asyncio.futures import Future
|
||||
from collections import defaultdict, deque
|
||||
from contextlib import contextmanager, suppress
|
||||
from functools import partial
|
||||
from functools import partial, wraps
|
||||
from inspect import isawaitable
|
||||
from os import environ
|
||||
from socket import socket
|
||||
@@ -87,7 +87,7 @@ from sanic.request import Request
|
||||
from sanic.response import BaseHTTPResponse, HTTPResponse, ResponseStream
|
||||
from sanic.router import Router
|
||||
from sanic.server.websockets.impl import ConnectionClosed
|
||||
from sanic.signals import Signal, SignalRouter
|
||||
from sanic.signals import Event, Signal, SignalRouter
|
||||
from sanic.touchup import TouchUp, TouchUpMeta
|
||||
from sanic.types.shared_ctx import SharedContext
|
||||
from sanic.worker.inspector import Inspector
|
||||
@@ -605,6 +605,19 @@ class Sanic(
|
||||
raise NotFound("Could not find signal %s" % event)
|
||||
return await wait_for(signal.ctx.event.wait(), timeout=timeout)
|
||||
|
||||
def report_exception(
|
||||
self, handler: Callable[[Sanic, Exception], Coroutine[Any, Any, None]]
|
||||
):
|
||||
@wraps(handler)
|
||||
async def report(exception: Exception) -> None:
|
||||
await handler(self, exception)
|
||||
|
||||
self.add_signal(
|
||||
handler=report, event=Event.SERVER_EXCEPTION_REPORT.value
|
||||
)
|
||||
|
||||
return report
|
||||
|
||||
def enable_websocket(self, enable=True):
|
||||
"""Enable or disable the support for websocket.
|
||||
|
||||
@@ -876,10 +889,12 @@ class Sanic(
|
||||
:raises ServerError: response 500
|
||||
"""
|
||||
response = None
|
||||
await self.dispatch(
|
||||
"server.lifecycle.exception",
|
||||
context={"exception": exception},
|
||||
)
|
||||
if not getattr(exception, "__dispatched__", False):
|
||||
... # DO NOT REMOVE THIS LINE. IT IS NEEDED FOR TOUCHUP.
|
||||
await self.dispatch(
|
||||
"server.exception.report",
|
||||
context={"exception": exception},
|
||||
)
|
||||
await self.dispatch(
|
||||
"http.lifecycle.exception",
|
||||
inline=True,
|
||||
@@ -1310,13 +1325,28 @@ class Sanic(
|
||||
app,
|
||||
loop,
|
||||
):
|
||||
if callable(task):
|
||||
async def do(task):
|
||||
try:
|
||||
task = task(app)
|
||||
except TypeError:
|
||||
task = task()
|
||||
if callable(task):
|
||||
try:
|
||||
task = task(app)
|
||||
except TypeError:
|
||||
task = task()
|
||||
if isawaitable(task):
|
||||
await task
|
||||
except CancelledError:
|
||||
error_logger.warning(
|
||||
f"Task {task} was cancelled before it completed."
|
||||
)
|
||||
raise
|
||||
except Exception as e:
|
||||
await app.dispatch(
|
||||
"server.exception.report",
|
||||
context={"exception": e},
|
||||
)
|
||||
raise
|
||||
|
||||
return task
|
||||
return do(task)
|
||||
|
||||
@classmethod
|
||||
def _loop_add_task(
|
||||
|
||||
@@ -16,11 +16,11 @@ from sanic.models.handler_types import SignalHandler
|
||||
|
||||
|
||||
class Event(Enum):
|
||||
SERVER_EXCEPTION_REPORT = "server.exception.report"
|
||||
SERVER_INIT_AFTER = "server.init.after"
|
||||
SERVER_INIT_BEFORE = "server.init.before"
|
||||
SERVER_SHUTDOWN_AFTER = "server.shutdown.after"
|
||||
SERVER_SHUTDOWN_BEFORE = "server.shutdown.before"
|
||||
SERVER_LIFECYCLE_EXCEPTION = "server.lifecycle.exception"
|
||||
HTTP_LIFECYCLE_BEGIN = "http.lifecycle.begin"
|
||||
HTTP_LIFECYCLE_COMPLETE = "http.lifecycle.complete"
|
||||
HTTP_LIFECYCLE_EXCEPTION = "http.lifecycle.exception"
|
||||
@@ -40,11 +40,11 @@ class Event(Enum):
|
||||
|
||||
RESERVED_NAMESPACES = {
|
||||
"server": (
|
||||
Event.SERVER_EXCEPTION_REPORT.value,
|
||||
Event.SERVER_INIT_AFTER.value,
|
||||
Event.SERVER_INIT_BEFORE.value,
|
||||
Event.SERVER_SHUTDOWN_AFTER.value,
|
||||
Event.SERVER_SHUTDOWN_BEFORE.value,
|
||||
Event.SERVER_LIFECYCLE_EXCEPTION.value,
|
||||
),
|
||||
"http": (
|
||||
Event.HTTP_LIFECYCLE_BEGIN.value,
|
||||
@@ -174,11 +174,12 @@ class SignalRouter(BaseRouter):
|
||||
if self.ctx.app.debug and self.ctx.app.state.verbosity >= 1:
|
||||
error_logger.exception(e)
|
||||
|
||||
if event != Event.SERVER_LIFECYCLE_EXCEPTION.value:
|
||||
if event != Event.SERVER_EXCEPTION_REPORT.value:
|
||||
await self.dispatch(
|
||||
Event.SERVER_LIFECYCLE_EXCEPTION.value,
|
||||
Event.SERVER_EXCEPTION_REPORT.value,
|
||||
context={"exception": e},
|
||||
)
|
||||
setattr(e, "__dispatched__", True)
|
||||
raise e
|
||||
finally:
|
||||
for signal_event in events:
|
||||
|
||||
Reference in New Issue
Block a user