示例#1
0
async def server_call_wrapper(wrapped, _instance, args, kwargs):
    """
    Wraps the main fastapi server request entrypoint - which is
    the ServerErrorMiddleware __call_ function.
    :param wrapped: wrapt's wrapped
    :param instance: wrapt's instance
    :param args: wrapt's args
    :param kwargs: wrapt's kwargs
    """
    # Skip on Lambda environment since it's not relevant and might be duplicate
    if is_lambda_env() or not args or len(args) != 3:
        return await wrapped(*args, **kwargs)

    scope = args[0]
    if not scope or scope.get('type', '') != 'http':
        return await wrapped(*args, **kwargs)

    trace = None
    try:
        epsagon.trace.trace_factory.switch_to_multiple_traces()
        unique_id = str(uuid.uuid4())
        trace = epsagon.trace.trace_factory.get_or_create_trace(
            unique_id=unique_id)
        trace.prepare()
        scope[EPSAGON_MARKER] = {
            SCOPE_UNIQUE_ID: unique_id,
        }
    except Exception:  # pylint: disable=broad-except
        _clean_trace(trace)
        return await wrapped(*args, **kwargs)

    response = None
    raised_error = None
    sent_trace = False
    epsagon_scope = scope[EPSAGON_MARKER]
    try:
        response = await wrapped(*args, **kwargs)
    except Exception as exception:  # pylint: disable=broad-except
        raised_error = exception

    if trace.runner and not epsagon_scope.get(SCOPE_IGNORE_REQUEST):
        try:
            if raised_error:
                traceback_data = get_traceback_data_from_exception(
                    raised_error)
                trace.runner.set_exception(raised_error, traceback_data)
                trace.runner.update_status_code(DEFAULT_ERROR_STATUS_CODE,
                                                override=False)
            await run_in_threadpool(epsagon.trace.trace_factory.send_traces,
                                    trace=trace)
            sent_trace = True
        except Exception as exception:  # pylint: disable=broad-except
            print_debug('Failed to send traces: {}'.format(exception))

    scope.pop(EPSAGON_MARKER, None)
    if not sent_trace:
        _clean_trace(trace)
    if raised_error:
        raise raised_error from None
    return response
示例#2
0
        async def custom_route_handler(request: Request) -> Response:
            """
            Traces given request and its response.
            :param request: to trace
            """
            should_ignore_request = True
            try:
                epsagon.trace.trace_factory.switch_to_async_tracer()
                if not ignore_request('', request.url.path.lower()):
                    should_ignore_request = False
                    trace = epsagon.trace.trace_factory.get_or_create_trace()
                    trace.prepare()

            except Exception as exception: # pylint: disable=W0703
                return await original_route_handler(request)

            if should_ignore_request:
                return await original_route_handler(request)

            runner = None
            response = None
            try:
                body = await request.json()
            except json.decoder.JSONDecodeError:
                body = ''
            try:
                runner = FastapiRunner(time.time(), request, json.dumps(body))
                trace.set_runner(runner)
                collect_container_metadata(runner.resource['metadata'])
            except Exception as exception: # pylint: disable=W0703
                warnings.warn('Could not extract request', EpsagonWarning)
            raised_err = None
            try:
                response: Response = await original_route_handler(request)
            except Exception as exception:  # pylint: disable=W0703
                raised_err = exception
                traceback_data = get_traceback_data_from_exception(exception)
                trace.runner.set_exception(exception, traceback_data)

            try:
                if not raised_err and response is not None and runner:
                    if ignore_request(
                            response.headers.get('Content-Type', '').lower(),
                            ''
                    ):
                        return response

                    runner.update_response(response)

                if runner:
                    epsagon.trace.trace_factory.send_traces()
            except Exception as exception:  # pylint: disable=W0703
                print_debug('Failed to send traces: {}'.format(exception))

            if raised_err:
                raise raised_err

            return response
示例#3
0
async def AiohttpMiddleware(request, handler):
    """
    aiohttp middleware to create a runner with event details
    :param request: incoming request data
    :param handler: original handler
    :return: response data from the handler
    """
    print_debug('[aiohttp] started middleware')
    epsagon.trace.trace_factory.switch_to_async_tracer()

    if (ignore_request('', request.path.lower())
            or is_ignored_endpoint(request.path.lower())):
        print_debug('[aiohttp] ignoring request')
        return await handler(request)

    trace = epsagon.trace.trace_factory.get_or_create_trace()
    trace.prepare()
    runner = None
    response = None

    try:
        body = await request.text()
        print_debug('[aiohttp] got body')
        runner = AiohttpRunner(time.time(), request, body, handler)
        trace.set_runner(runner)
        collect_container_metadata(runner.resource['metadata'])
        print_debug('[aiohttp] initialized runner')
    except Exception as exception:  # pylint: disable=W0703
        warnings.warn('Could not extract request', EpsagonWarning)

    raised_err = None
    try:
        response = await handler(request)
        print_debug('[aiohttp] got response')
    except HTTPNotFound:
        # Ignoring 404s
        epsagon.trace.trace_factory.pop_trace(trace)
        raise
    except Exception as exception:  # pylint: disable=W0703
        raised_err = exception
        traceback_data = get_traceback_data_from_exception(exception)
        trace.runner.set_exception(exception, traceback_data)

    if response is not None and runner:
        if ignore_request(response.content_type.lower(), ''):
            return response

        runner.update_response(response)

    if runner:
        print_debug('[aiohttp] sending trace')
        epsagon.trace.trace_factory.send_traces()
    if raised_err:
        print_debug('[aiohttp] raising error')
        raise raised_err
    print_debug('[aiohttp] middleware done')
    return response
示例#4
0
    def process_exception(self, request, process_exception):
        """
        Processes and appends a given exception to the current trace
        """
        if not process_exception:
            return

        if (not hasattr(request, 'epsagon_trace')
                or not request.epsagon_trace.runner):
            return

        traceback_data = get_traceback_data_from_exception(process_exception)

        request.epsagon_trace.runner.set_exception(process_exception,
                                                   traceback_data, False)
示例#5
0
    def _teardown_request(self, exception):
        """
        Runs at the end of the request. Exception will be passed if happens.
        If no flask url rule exists for a request, then the request trace
        will be passed.
        :param exception: Exception (or None).
        :return: None.
        """
        if self.ignored_request:
            return
        trace = epsagon.trace.trace_factory.get_or_create_trace()
        if exception and trace.runner:
            traceback_data = get_traceback_data_from_exception(exception)
            trace.runner.set_exception(exception, traceback_data)
        # Ignoring endpoint, only if no error happened.
        if (not exception and request.url_rule
                and request.url_rule.rule in self.ignored_endpoints):
            return

        epsagon.trace.trace_factory.send_traces()
示例#6
0
async def AiohttpMiddleware(request, handler):
    """
    aiohttp middleware to create a runner with event details
    :param request: incoming request data
    :param handler: original handler
    :return: response data from the handler
    """
    epsagon.trace.trace_factory.switch_to_async_tracer()

    if ignore_request('', request.path.lower()):
        return await handler(request)

    trace = epsagon.trace.trace_factory.get_or_create_trace()
    trace.prepare()
    runner = None
    response = None

    try:
        body = await request.text()
        runner = AiohttpRunner(time.time(), request, body, handler)
        trace.set_runner(runner)
        collect_container_metadata(runner.resource['metadata'])
    except Exception as exception:  # pylint: disable=W0703
        warnings.warn('Could not extract request', EpsagonWarning)

    try:
        response = await handler(request)
    except Exception as exception:  # pylint: disable=W0703
        traceback_data = get_traceback_data_from_exception(exception)
        trace.runner.set_exception(exception, traceback_data)

    if response is not None and runner:
        if ignore_request(response.content_type.lower(), ''):
            return response

        runner.update_response(response)

    if runner:
        epsagon.trace.trace_factory.send_traces()

    return response
示例#7
0
 def process_exception(self, _, process_exception):
     if process_exception:
         traceback_data = get_traceback_data_from_exception(
             process_exception)
         self.runner.set_exception(process_exception, traceback_data, False)