Skip to content

Commit 73bb478

Browse files
ahmedetefysentry-bot
and
sentry-bot
authored
feat(integration): Add support for Sanic >=21.3 (getsentry#1146)
* feat(integration): Add support for Sanic >=21.3 * PR changes requested * Fixed failing test + consistent transaction names * fix: Formatting * Trigger Build * Small refactor * Removed python 3.9 sanic 19 env due to lack of support * Added checks for splitting app name from route name Co-authored-by: sentry-bot <markus+ghbot@sentry.io>
1 parent dd91a8b commit 73bb478

File tree

3 files changed

+71
-10
lines changed

3 files changed

+71
-10
lines changed

sentry_sdk/integrations/sanic.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,29 @@ async def sentry_handle_request(self, request, *args, **kwargs):
9696

9797
old_router_get = Router.get
9898

99-
def sentry_router_get(self, request):
100-
# type: (Any, Request) -> Any
101-
rv = old_router_get(self, request)
99+
def sentry_router_get(self, *args):
100+
# type: (Any, Union[Any, Request]) -> Any
101+
rv = old_router_get(self, *args)
102102
hub = Hub.current
103103
if hub.get_integration(SanicIntegration) is not None:
104104
with capture_internal_exceptions():
105105
with hub.configure_scope() as scope:
106-
scope.transaction = rv[0].__name__
106+
if version >= (21, 3):
107+
# Sanic versions above and including 21.3 append the app name to the
108+
# route name, and so we need to remove it from Route name so the
109+
# transaction name is consistent across all versions
110+
sanic_app_name = self.ctx.app.name
111+
sanic_route = rv[0].name
112+
113+
if sanic_route.startswith("%s." % sanic_app_name):
114+
# We add a 1 to the len of the sanic_app_name because there is a dot
115+
# that joins app name and the route name
116+
# Format: app_name.route_name
117+
sanic_route = sanic_route[len(sanic_app_name) + 1 :]
118+
119+
scope.transaction = sanic_route
120+
else:
121+
scope.transaction = rv[0].__name__
107122
return rv
108123

109124
Router.get = sentry_router_get

tests/integrations/sanic/test_sanic.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@
99
from sentry_sdk.integrations.sanic import SanicIntegration
1010

1111
from sanic import Sanic, request, response, __version__ as SANIC_VERSION_RAW
12+
from sanic.response import HTTPResponse
1213
from sanic.exceptions import abort
1314

1415
SANIC_VERSION = tuple(map(int, SANIC_VERSION_RAW.split(".")))
1516

1617

1718
@pytest.fixture
1819
def app():
19-
app = Sanic(__name__)
20+
if SANIC_VERSION >= (20, 12):
21+
# Build (20.12.0) adds a feature where the instance is stored in an internal class
22+
# registry for later retrieval, and so add register=False to disable that
23+
app = Sanic(__name__, register=False)
24+
else:
25+
app = Sanic(__name__)
2026

2127
@app.route("/message")
2228
def hi(request):
@@ -166,11 +172,46 @@ async def task(i):
166172
if SANIC_VERSION >= (19,):
167173
kwargs["app"] = app
168174

169-
await app.handle_request(
170-
request.Request(**kwargs),
171-
write_callback=responses.append,
172-
stream_callback=responses.append,
173-
)
175+
if SANIC_VERSION >= (21, 3):
176+
try:
177+
app.router.reset()
178+
app.router.finalize()
179+
except AttributeError:
180+
...
181+
182+
class MockAsyncStreamer:
183+
def __init__(self, request_body):
184+
self.request_body = request_body
185+
self.iter = iter(self.request_body)
186+
self.response = b"success"
187+
188+
def respond(self, response):
189+
responses.append(response)
190+
patched_response = HTTPResponse()
191+
patched_response.send = lambda end_stream: asyncio.sleep(0.001)
192+
return patched_response
193+
194+
def __aiter__(self):
195+
return self
196+
197+
async def __anext__(self):
198+
try:
199+
return next(self.iter)
200+
except StopIteration:
201+
raise StopAsyncIteration
202+
203+
patched_request = request.Request(**kwargs)
204+
patched_request.stream = MockAsyncStreamer([b"hello", b"foo"])
205+
206+
await app.handle_request(
207+
patched_request,
208+
)
209+
else:
210+
await app.handle_request(
211+
request.Request(**kwargs),
212+
write_callback=responses.append,
213+
stream_callback=responses.append,
214+
)
174215

175216
(r,) = responses
176217
assert r.status == 200

tox.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ envlist =
3939

4040
{py3.5,py3.6,py3.7}-sanic-{0.8,18}
4141
{py3.6,py3.7}-sanic-19
42+
{py3.6,py3.7,py3.8}-sanic-20
43+
{py3.7,py3.8,py3.9}-sanic-21
4244

4345
# TODO: Add py3.9
4446
{pypy,py2.7}-celery-3
@@ -139,6 +141,9 @@ deps =
139141
sanic-0.8: sanic>=0.8,<0.9
140142
sanic-18: sanic>=18.0,<19.0
141143
sanic-19: sanic>=19.0,<20.0
144+
sanic-20: sanic>=20.0,<21.0
145+
sanic-21: sanic>=21.0,<22.0
146+
{py3.7,py3.8,py3.9}-sanic-21: sanic_testing
142147
{py3.5,py3.6}-sanic: aiocontextvars==0.2.1
143148
sanic: aiohttp
144149
py3.5-sanic: ujson<4

0 commit comments

Comments
 (0)