Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
# -*- 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)
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
# -*- 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']