def setup_once(): # type: () -> None try: version = tuple(map(int, AIOHTTP_VERSION.split(".")[:2])) except (TypeError, ValueError): raise DidNotEnable( "AIOHTTP version unparseable: {}".format(AIOHTTP_VERSION)) if version < (3, 4): raise DidNotEnable("AIOHTTP 3.4 or newer required.") if not HAS_REAL_CONTEXTVARS: # We better have contextvars or we're going to leak state between # requests. raise DidNotEnable( "The aiohttp integration for Sentry requires Python 3.7+ " " or aiocontextvars package." + CONTEXTVARS_ERROR_MESSAGE) ignore_logger("aiohttp.server") old_handle = Application._handle async def sentry_app_handle(self, request, *args, **kwargs): # type: (Any, Request, *Any, **Any) -> Any hub = Hub.current if hub.get_integration(AioHttpIntegration) is None: return await old_handle(self, request, *args, **kwargs) weak_request = weakref.ref(request) with Hub(Hub.current) as hub: # Scope data will not leak between requests because aiohttp # create a task to wrap each request. with hub.configure_scope() as scope: scope.clear_breadcrumbs() scope.add_event_processor( _make_request_processor(weak_request)) transaction = Transaction.continue_from_headers( request.headers, op="http.server", # If this transaction name makes it to the UI, AIOHTTP's # URL resolver did not find a route or died trying. name="generic AIOHTTP request", ) with hub.start_transaction(transaction): try: response = await old_handle(self, request) except HTTPException as e: transaction.set_http_status(e.status_code) raise except asyncio.CancelledError: transaction.set_status("cancelled") raise except Exception: # This will probably map to a 500 but seems like we # have no way to tell. Do not set span status. reraise(*_capture_exception(hub)) transaction.set_http_status(response.status) return response Application._handle = sentry_app_handle old_urldispatcher_resolve = UrlDispatcher.resolve async def sentry_urldispatcher_resolve(self, request): # type: (UrlDispatcher, Request) -> AbstractMatchInfo rv = await old_urldispatcher_resolve(self, request) hub = Hub.current integration = hub.get_integration(AioHttpIntegration) name = None try: if integration.transaction_style == "handler_name": name = transaction_from_function(rv.handler) elif integration.transaction_style == "method_and_path_pattern": route_info = rv.get_info() pattern = route_info.get("path") or route_info.get( "formatter") name = "{} {}".format(request.method, pattern) except Exception: pass if name is not None: with Hub.current.configure_scope() as scope: scope.transaction = name return rv UrlDispatcher.resolve = sentry_urldispatcher_resolve
# -*- coding: utf-8 -*- from aiohttp import __version__ as aiohttp_version from typing import Optional from urllib.parse import urlsplit, urlencode, SplitResult, urlunsplit try: from yarl import URL print(aiohttp_version) if aiohttp_version.split('.')[:2] == ['1', '0']: # yarl was introduced in version 1.1 raise ImportError yarl_available = True except ImportError: class URL(str): pass yarl_available = False __all__ = ['URL', 'merge_url_params'] def _vanilla_merge_url_params(url: str, params: Optional[dict]) -> str: if not params: return url url_split = urlsplit(url) if url_split.query: qs = "{}&{}".format(url_split.query, urlencode(params)) else: qs = urlencode(params)
def setup_once(): # type: () -> None try: version = tuple(map(int, AIOHTTP_VERSION.split("."))) except (TypeError, ValueError): raise DidNotEnable( "AIOHTTP version unparseable: {}".format(version)) if version < (3, 4): raise DidNotEnable("AIOHTTP 3.4 or newer required.") 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+ " " or aiocontextvars package") ignore_logger("aiohttp.server") old_handle = Application._handle async def sentry_app_handle(self, request, *args, **kwargs): # type: (Any, Request, *Any, **Any) -> Any async def inner(): # type: () -> Any hub = Hub.current if hub.get_integration(AioHttpIntegration) is None: return await old_handle(self, request, *args, **kwargs) weak_request = weakref.ref(request) with Hub(Hub.current) as hub: with hub.configure_scope() as scope: scope.clear_breadcrumbs() scope.add_event_processor( _make_request_processor(weak_request)) span = Span.continue_from_headers(request.headers) span.op = "http.server" # If this transaction name makes it to the UI, AIOHTTP's # URL resolver did not find a route or died trying. span.transaction = "generic AIOHTTP request" with hub.start_span(span): try: response = await old_handle(self, request) except HTTPException as e: span.set_http_status(e.status_code) raise except asyncio.CancelledError: span.set_status("cancelled") raise except Exception: # This will probably map to a 500 but seems like we # have no way to tell. Do not set span status. reraise(*_capture_exception(hub)) span.set_http_status(response.status) return response # 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 old_urldispatcher_resolve = UrlDispatcher.resolve async def sentry_urldispatcher_resolve(self, request): # type: (UrlDispatcher, Request) -> AbstractMatchInfo rv = await old_urldispatcher_resolve(self, request) name = None try: name = transaction_from_function(rv.handler) except Exception: pass if name is not None: with Hub.current.configure_scope() as scope: scope.transaction = name return rv UrlDispatcher.resolve = sentry_urldispatcher_resolve
# -*- coding: utf-8 -*- from aiohttp import __version__ as aiohttp_version, StreamReader from typing import Optional from urllib.parse import urlsplit, urlencode, SplitResult, urlunsplit try: from yarl import URL if aiohttp_version.split('.')[:2] == ['1', '0']: # yarl was introduced in version 1.1 raise ImportError yarl_available = True except ImportError: class URL(str): pass yarl_available = False if int(aiohttp_version.split('.')[0]) >= 3: from aiohttp.client_proto import ResponseHandler def stream_reader(): protocol = ResponseHandler() return StreamReader(protocol) else: def stream_reader(): return StreamReader() __all__ = ['URL', 'merge_url_params']