diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 4fa78bdb64..170774354e 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -734,15 +734,50 @@ def realign_remark(remark): ) -HAS_REAL_CONTEXTVARS = True +def _is_threading_local_monkey_patched(): + # type: () -> bool + try: + from gevent.monkey import is_object_patched # type: ignore + + if is_object_patched("_threading", "local"): + return True + except ImportError: + pass + + try: + from eventlet.patcher import is_monkey_patched # type: ignore + + if is_monkey_patched("thread"): + return True + except ImportError: + pass + + return False + -try: - from contextvars import ContextVar # type: ignore +IS_THREADING_LOCAL_MONKEY_PATCHED = _is_threading_local_monkey_patched() +del _is_threading_local_monkey_patched - if not PY2 and sys.version_info < (3, 7): - import aiocontextvars # type: ignore # noqa -except ImportError: - HAS_REAL_CONTEXTVARS = False + +def _get_contextvars(): + # () -> (bool, Type) + """ + Try to import contextvars and use it if it's deemed safe. We should not use + contextvars if gevent or eventlet have patched thread locals, as + contextvars are unaffected by that patch. + + https://github.com/gevent/gevent/issues/1407 + """ + if not IS_THREADING_LOCAL_MONKEY_PATCHED: + try: + from contextvars import ContextVar # type: ignore + + if not PY2 and sys.version_info < (3, 7): + import aiocontextvars # type: ignore # noqa + + return True, ContextVar + except ImportError: + pass from threading import local @@ -759,6 +794,12 @@ def get(self, default): def set(self, value): setattr(self._local, "value", value) + return False, ContextVar + + +HAS_REAL_CONTEXTVARS, ContextVar = _get_contextvars() +del _get_contextvars + def transaction_from_function(func): # type: (Callable[..., Any]) -> Optional[str] diff --git a/tox.ini b/tox.ini index af53b4914d..47243e9081 100644 --- a/tox.ini +++ b/tox.ini @@ -27,7 +27,7 @@ envlist = {pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-falcon-1.4 {pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-falcon-2.0 - {py3.5,py3.6,py3.7}-sanic-{0.8,18,19} + {py3.5,py3.6,py3.7}-sanic-{0.8,18} {pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-celery-{4.1,4.2,4.3} {pypy,py2.7}-celery-3 @@ -79,7 +79,6 @@ deps = sanic-0.8: sanic>=0.8,<0.9 sanic-18: sanic>=18.0,<19.0 - sanic-19: sanic>=19.0,<20.0 {py3.5,py3.6}-sanic: aiocontextvars==0.2.1 sanic: aiohttp