8000 use contextvars backport for aiohttp and sanic support in py3.6 by antonio-antuan · Pull Request #293 · getsentry/sentry-python · GitHub
[go: up one dir, main page]

Skip to content

use contextvars backport for aiohttp and sanic support in py3.6 #293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions sentry_sdk/integrations/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
from sentry_sdk.integrations import Integration
from sentry_sdk.integrations.logging import ignore_logger
from sentry_sdk.integrations._wsgi_common import _filter_headers
from sentry_sdk.utils import capture_internal_exceptions, event_from_exception
from sentry_sdk.utils import (
capture_internal_exceptions,
event_from_exception,
HAS_REAL_CONTEXTVARS,
)

import asyncio
from aiohttp.web import Application, HTTPException # type: ignore
Expand All @@ -27,11 +31,12 @@ class AioHttpIntegration(Integration):
@staticmethod
def setup_once():
# type: () -> None
if sys.version_info < (3, 7):
if not HAS_REAL_CONTEXTVARS:
# We better have contextvars or we're going to leak state between
# requests.
raise RuntimeError(
"The aiohttp integration for Sentry requires Python 3.7+"
"The aiohttp integration for Sentry requires Python 3.7+ "
" or aiocontextvars package"
)

ignore_logger("aiohttp.server")
Expand Down Expand Up @@ -61,7 +66,10 @@ async def inner():

return response

return await asyncio.create_task(inner())
# Explicitly wrap in task such that current contextvar context is
# copied. Just doing `return await inner()` will leak scope data
# between requests.
return await asyncio.get_event_loop().create_task(inner())

Application._handle = sentry_app_handle

Expand Down
17 changes: 12 additions & 5 deletions sentry_sdk/integrations/sanic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

from sentry_sdk._compat import urlparse, reraise
from sentry_sdk.hub import Hub
from sentry_sdk.utils import capture_internal_exceptions, event_from_exception
from sentry_sdk.utils import (
capture_internal_exceptions,
event_from_exception,
HAS_REAL_CONTEXTVARS,
)
from sentry_sdk.integrations import Integration
from sentry_sdk.integrations._wsgi_common import RequestExtractor, _filter_headers
from sentry_sdk.integrations.logging import ignore_logger
Expand Down Expand Up @@ -34,10 +38,13 @@ class SanicIntegration(Integration):
@staticmethod
def setup_once():
# type: () -> None
if sys.version_info < (3, 7):
# Sanic is async. We better have contextvars or we're going to leak
# state between requests.
raise RuntimeError("The sanic integration for Sentry requires Python 3.7+")
if not HAS_REAL_CONTEXTVARS:
# We better have contextvars or we're going to leak state between
# requests.
raise RuntimeError(
"The sanic integration for Sentry requires Python 3.7+ "
" or aiocontextvars package"
)

# Sanic 0.8 and older creates a logger named "root" and puts a
# stringified version of every exception in there (without exc_info),
Expand Down
7 changes: 7 additions & 0 deletions sentry_sdk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,9 +868,16 @@ def realign_remark(remark):
)


HAS_REAL_CONTEXTVARS = True

try:
from contextvars import ContextVar # type: ignore

if not PY2 and sys.version_info < (3, 7):
import aiocontextvars # type: ignore # noqa
except ImportError:
HAS_REAL_CONTEXTVARS = False

from threading import local

class ContextVar(object): # type: ignore
Expand Down
2 changes: 1 addition & 1 deletion test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ pytest-xdist==1.23.0
tox==3.7.0
Werkzeug==0.14.1
pytest-localserver==0.4.1
pytest-cov==2.6.0
pytest-cov==2.6.0
2 changes: 1 addition & 1 deletion tests/integrations/aiohttp/test_aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async def hello(request):
assert request["env"] == {"REMOTE_ADDR": "127.0.0.1"}
assert request["method"] == "GET"
assert request["query_string"] == ""
assert request["url"] == f"http://{host}/"
assert request["url"] == "http://{host}/".format(host=host)
assert request["headers"] == {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
Expand Down
13 changes: 11 additions & 2 deletions tests/integrations/sanic/test_sanic.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sys

import random
import asyncio

Expand Down Expand Up @@ -140,7 +142,9 @@ async def task(i):

await app.handle_request(
request.Request(
url_bytes=f"http://localhost/context-check/{i}".encode("ascii"),
url_bytes="http://localhost/context-check/{i}".format(i=i).encode(
"ascii"
),
headers={},
version="1.1",
method="GET",
Expand All @@ -156,7 +160,12 @@ async def task(i):
async def runner():
await asyncio.gather(*(task(i) for i in range(1000)))

asyncio.run(runner())
if sys.version_info < (3, 7):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(runner())
else:
asyncio.run(runner())

with configure_scope() as scope:
assert not scope._tags
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ envlist =

{pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-flask-{1.0,0.11,0.12,dev}

py3.7-sanic-0.8
{py3.5,py3.6,py3.7}-sanic-0.8

{pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-celery-{4.1,4.2}
{pypy,py2.7}-celery-3
Expand Down Expand Up @@ -62,6 +62,7 @@ deps =
flask-dev: git+https://github.com/pallets/flask.git#egg=flask

sanic-0.8: sanic>=0.8,<0.9
{py3.5,py3.6}-sanic-0.8: aiocontextvars==0.2.1
sanic: aiohttp

celery-3: Celery>=3.1,<4.0
Expand Down
0