Add convenience method for exception reporting (#2792)

This commit is contained in:
Adam Hopkins
2023-07-18 00:21:55 +03:00
committed by GitHub
parent 31d7ba8f8c
commit 9cbe1fb8ad
4 changed files with 160 additions and 16 deletions

View File

@@ -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(

View File

@@ -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: