Beispiel #1
0
    def process_response(self, req, resp, resource, req_succeeded=None):
        if self.client and req.user_agent != 'mcod-heartbeat':
            rule = route_to_name(req.uri_template,
                                 prefix='api',
                                 method=req.method)
            elasticapm.set_context(
                lambda: get_data_from_request(
                    req,
                    capture_body=self.client.config.capture_body in
                    ("transactions", "all"),
                    capture_headers=self.client.config.capture_headers,
                ),
                "request",
            )
            elasticapm.set_context(
                lambda: get_data_from_response(
                    resp, capture_headers=self.client.config.capture_headers),
                "response")

            result = resp.status
            elasticapm.set_transaction_name(rule, override=False)
            if hasattr(req, 'user') and req.user.is_authenticated:
                elasticapm.set_user_context(email=req.user.email,
                                            user_id=req.user.id)

            elasticapm.set_transaction_result(result, override=False)
            # Instead of calling end_transaction here, we defer the call until the response is closed.
            # This ensures that we capture things that happen until the WSGI server closes the response.
            self.client.end_transaction(rule, result)
Beispiel #2
0
    async def _request_started(self, request: Request):
        """Captures the begin of the request processing to APM.

        Args:
            request (Request)
        """
        # When we consume the body, we replace the streaming mechanism with
        # a mocked version -- this workaround came from
        # https://github.com/encode/starlette/issues/495#issuecomment-513138055
        # and we call the workaround here to make sure that regardless of
        # `capture_body` settings, we will have access to the body if we need it.
        if self.client.config.capture_body != "off":
            await get_body(request)

        if not self.client.should_ignore_url(request.url.path):
            trace_parent = TraceParent.from_headers(dict(request.headers))
            self.client.begin_transaction("request", trace_parent=trace_parent)

            await set_context(
                lambda: get_data_from_request(request, self.client.config,
                                              constants.TRANSACTION),
                "request")
            transaction_name = self.get_route_name(request) or request.url.path
            elasticapm.set_transaction_name("{} {}".format(
                request.method, transaction_name),
                                            override=False)
Beispiel #3
0
    async def call(self, module, method, wrapped, instance, args, kwargs):
        # Late import to avoid ImportErrors
        from elasticapm.contrib.tornado.utils import get_data_from_request, get_data_from_response

        request = instance.request
        trace_parent = TraceParent.from_headers(request.headers)
        client = instance.application.elasticapm_client
        client.begin_transaction("request", trace_parent=trace_parent)
        elasticapm.set_context(
            lambda: get_data_from_request(instance, request, client.config,
                                          constants.TRANSACTION), "request")
        # TODO: Can we somehow incorporate the routing rule itself here?
        elasticapm.set_transaction_name("{} {}".format(
            request.method,
            type(instance).__name__),
                                        override=False)

        ret = await wrapped(*args, **kwargs)

        elasticapm.set_context(
            lambda: get_data_from_response(instance, client.config, constants.
                                           TRANSACTION), "response")
        result = "HTTP {}xx".format(instance.get_status() // 100)
        elasticapm.set_transaction_result(result, override=False)
        client.end_transaction()

        return ret
Beispiel #4
0
    async def call(self, module, method, wrapped, instance, args, kwargs):
        if not hasattr(instance.application, "elasticapm_client"):
            # If tornado was instrumented but not as the main framework
            # (i.e. in Flower), we should skip it.
            return await wrapped(*args, **kwargs)

        # Late import to avoid ImportErrors
        from elasticapm.contrib.tornado.utils import get_data_from_request, get_data_from_response

        request = instance.request
        trace_parent = TraceParent.from_headers(request.headers)
        client = instance.application.elasticapm_client
        client.begin_transaction("request", trace_parent=trace_parent)
        elasticapm.set_context(
            lambda: get_data_from_request(instance, request, client.config,
                                          constants.TRANSACTION), "request")
        # TODO: Can we somehow incorporate the routing rule itself here?
        elasticapm.set_transaction_name("{} {}".format(
            request.method,
            type(instance).__name__),
                                        override=False)

        ret = await wrapped(*args, **kwargs)

        elasticapm.set_context(
            lambda: get_data_from_response(instance, client.config, constants.
                                           TRANSACTION), "response")
        status = instance.get_status()
        result = "HTTP {}xx".format(status // 100)
        elasticapm.set_transaction_result(result, override=False)
        elasticapm.set_transaction_outcome(http_status_code=status)
        client.end_transaction()

        return ret
Beispiel #5
0
 def request_finished(self, app, response):
     if not self.app.debug or self.client.config.debug:
         rule = request.url_rule.rule if request.url_rule is not None else ""
         rule = build_name_with_http_method_prefix(rule, request)
         elasticapm.set_context(
             lambda: get_data_from_request(
                 request,
                 capture_body=self.client.config.capture_body in
                 ("transactions", "all"),
                 capture_headers=self.client.config.capture_headers,
             ),
             "request",
         )
         elasticapm.set_context(
             lambda: get_data_from_response(response,
                                            capture_headers=self.client.
                                            config.capture_headers),
             "response")
         if response.status_code:
             result = "HTTP {}xx".format(response.status_code // 100)
         else:
             result = response.status
         elasticapm.set_transaction_name(rule, override=False)
         elasticapm.set_transaction_result(result, override=False)
         # Instead of calling end_transaction here, we defer the call until the response is closed.
         # This ensures that we capture things that happen until the WSGI server closes the response.
         response.call_on_close(self.client.end_transaction)
Beispiel #6
0
    def process_response(self, request, response):
        if django_settings.DEBUG and not self.client.config.debug:
            return response
        try:
            if hasattr(response, "status_code"):
                transaction_name = None
                if self.client.config.django_transaction_name_from_route and hasattr(request.resolver_match, "route"):
                    transaction_name = request.resolver_match.route
                elif getattr(request, "_elasticapm_view_func", False):
                    transaction_name = get_name_from_func(request._elasticapm_view_func)
                if transaction_name:
                    transaction_name = build_name_with_http_method_prefix(transaction_name, request)
                    elasticapm.set_transaction_name(transaction_name, override=False)

                elasticapm.set_context(
                    lambda: self.client.get_data_from_request(request, constants.TRANSACTION), "request"
                )
                elasticapm.set_context(
                    lambda: self.client.get_data_from_response(response, constants.TRANSACTION), "response"
                )
                elasticapm.set_context(lambda: self.client.get_user_info(request), "user")
                elasticapm.set_transaction_result("HTTP {}xx".format(response.status_code // 100), override=False)
                elasticapm.set_transaction_outcome(http_status_code=response.status_code, override=False)
        except Exception:
            self.client.error_logger.error("Exception during timing of request", exc_info=True)
        return response
Beispiel #7
0
 def process_response(self, request: HttpRequest, response: HttpResponse):
     if django_settings.DEBUG and not self.client.config.debug:
         return response
     try:
         if hasattr(response, "status_code"):
             if not getattr(request, "_elasticapm_name_set", False):
                 elasticapm.set_transaction_name(
                     self.get_transaction_name(request), override=False)
             elasticapm.set_context(
                 lambda: self.client.get_data_from_request(
                     request, constants.TRANSACTION), "request")
             elasticapm.set_context(
                 lambda: self.client.get_data_from_response(
                     response, constants.TRANSACTION), "response")
             elasticapm.set_context(
                 lambda: self.client.get_user_info(request), "user")
             elasticapm.set_transaction_result("HTTP {}xx".format(
                 response.status_code // 100),
                                               override=False)
             elasticapm.set_transaction_outcome(
                 http_status_code=response.status_code, override=False)
     except Exception:
         self.client.error_logger.error(
             "Exception during timing of request", exc_info=True)
     return response
Beispiel #8
0
    def process_response(self, request, response):
        if django_settings.DEBUG and not self.client.config.debug:
            return response
        try:
            if hasattr(response, "status_code"):
                if getattr(request, "_elasticapm_view_func", False):
                    transaction_name = get_name_from_func(
                        request._elasticapm_view_func)
                    transaction_name = build_name_with_http_method_prefix(
                        transaction_name, request)
                    elasticapm.set_transaction_name(transaction_name,
                                                    override=False)

                elasticapm.set_context(
                    lambda: self.client.get_data_from_request(
                        request,
                        capture_body=self.client.config.capture_body in
                        ("all", "transactions")),
                    "request",
                )
                elasticapm.set_context(
                    lambda: self.client.get_data_from_response(response),
                    "response")
                elasticapm.set_context(
                    lambda: self.client.get_user_info(request), "user")
                elasticapm.set_transaction_result("HTTP {}xx".format(
                    response.status_code // 100),
                                                  override=False)
        except Exception:
            self.client.error_logger.error(
                "Exception during timing of request", exc_info=True)
        return response
    def process_response(self, request, response):
        if django_settings.DEBUG and not self.client.config.debug:
            return response
        try:
            if hasattr(response, 'status_code'):
                if getattr(request, '_elasticapm_view_func', False):
                    transaction_name = get_name_from_func(
                        request._elasticapm_view_func
                    )
                    transaction_name = build_name_with_http_method_prefix(
                        transaction_name,
                        request
                    )
                    elasticapm.set_transaction_name(transaction_name, override=False)

                elasticapm.set_context(lambda: self.client.get_data_from_request(
                    request,
                    capture_body=self.client.config.capture_body in ('all', 'transactions')
                ), 'request')
                elasticapm.set_context(lambda: self.client.get_data_from_response(response), 'response')
                elasticapm.set_context(lambda: self.client.get_user_info(request), 'user')
                elasticapm.set_transaction_result('HTTP {}xx'.format(response.status_code // 100), override=False)
        except Exception:
            self.client.error_logger.error(
                'Exception during timing of request',
                exc_info=True,
            )
        return response
Beispiel #10
0
    async def handle_request(request, handler):
        elasticapm_client = app.get(CLIENT_KEY)
        if elasticapm_client:
            request[CLIENT_KEY] = elasticapm_client
            trace_parent = AioHttpTraceParent.from_headers(request.headers)
            elasticapm_client.begin_transaction("request",
                                                trace_parent=trace_parent)
            resource = request.match_info.route.resource
            name = request.method
            if resource:
                # canonical has been added in 3.3, and returns one of path, formatter, prefix
                for attr in ("canonical", "_path", "_formatter", "_prefix"):
                    if hasattr(resource, attr):
                        name += " " + getattr(resource, attr)
                        break
                else:
                    name += " unknown route"
            else:
                name += " unknown route"
            elasticapm.set_transaction_name(name, override=False)
            elasticapm.set_context(
                lambda: get_data_from_request(
                    request,
                    capture_body=elasticapm_client.config.capture_body in
                    ("transactions", "all"),
                    capture_headers=elasticapm_client.config.capture_headers,
                ),
                "request",
            )

        try:
            response = await handler(request)
            elasticapm.set_transaction_result("HTTP {}xx".format(
                response.status // 100),
                                              override=False)
            elasticapm.set_context(
                lambda: get_data_from_response(
                    response,
                    capture_headers=elasticapm_client.config.capture_headers),
                "response",
            )
            return response
        except Exception:
            if elasticapm_client:
                elasticapm_client.capture_exception(
                    context={
                        "request":
                        get_data_from_request(request,
                                              capture_body=elasticapm_client.
                                              config.capture_body in (
                                                  "all", "errors"))
                    })
                elasticapm.set_transaction_result("HTTP 5xx", override=False)
                elasticapm.set_context({"status_code": 500}, "response")
            raise
        finally:
            elasticapm_client.end_transaction()
Beispiel #11
0
    async def handle_request(request, handler):
        elasticapm_client = app.get(CLIENT_KEY)
        if elasticapm_client:
            request[CLIENT_KEY] = elasticapm_client
            trace_parent = AioHttpTraceParent.from_headers(request.headers)
            elasticapm_client.begin_transaction("request",
                                                trace_parent=trace_parent)
            resource = request.match_info.route.resource
            name = request.method
            if resource:
                # canonical has been added in 3.3, and returns one of path, formatter, prefix
                for attr in ("canonical", "_path", "_formatter", "_prefix"):
                    if hasattr(resource, attr):
                        name += " " + getattr(resource, attr)
                        break
                else:
                    name += " unknown route"
            else:
                name += " unknown route"
            elasticapm.set_transaction_name(name, override=False)
            elasticapm.set_context(
                lambda: get_data_from_request(request, elasticapm_client.
                                              config, constants.TRANSACTION),
                "request")

        try:
            response = await handler(request)
            elasticapm.set_transaction_result("HTTP {}xx".format(
                response.status // 100),
                                              override=False)
            elasticapm.set_context(
                lambda: get_data_from_response(response, elasticapm_client.
                                               config, constants.TRANSACTION),
                "response")
            return response
        except Exception as exc:
            if elasticapm_client:
                elasticapm_client.capture_exception(
                    context={
                        "request":
                        get_data_from_request(
                            request, elasticapm_client.config, constants.ERROR)
                    })
                elasticapm.set_transaction_result("HTTP 5xx", override=False)
                elasticapm.set_context({"status_code": 500}, "response")
                # some exceptions are response-like, e.g. have headers and status code. Let's try and capture them
                if isinstance(exc, (Response, HTTPException)):
                    elasticapm.set_context(
                        lambda: get_data_from_response(
                            exc, elasticapm_client.config, constants.ERROR
                        ),  # noqa: F821
                        "response",
                    )

            raise
        finally:
            elasticapm_client.end_transaction()
Beispiel #12
0
    def __enter__(self):
        """
        Transaction setup
        """
        trace_parent = TraceParent.from_headers(self.event.get("headers", {}))

        global COLD_START
        cold_start = COLD_START
        COLD_START = False

        self.source = "other"
        transaction_type = "request"
        transaction_name = os.environ.get("AWS_LAMBDA_FUNCTION_NAME",
                                          self.name)

        self.httpmethod = nested_key(
            self.event, "requestContext", "httpMethod") or nested_key(
                self.event, "requestContext", "http", "method")
        if self.httpmethod:  # API Gateway
            self.source = "api"
            if os.environ.get("AWS_LAMBDA_FUNCTION_NAME"):
                transaction_name = "{} {}".format(
                    self.httpmethod, os.environ["AWS_LAMBDA_FUNCTION_NAME"])
            else:
                transaction_name = self.name
        elif "Records" in self.event and len(self.event["Records"]) == 1:
            record = self.event["Records"][0]
            if record.get("eventSource") == "aws:s3":  # S3
                self.source = "s3"
                transaction_name = "{} {}".format(
                    record["eventName"], record["s3"]["bucket"]["name"])
            elif record.get("EventSource") == "aws:sns":  # SNS
                self.source = "sns"
                transaction_type = "messaging"
                transaction_name = "RECEIVE {}".format(
                    record["Sns"]["TopicArn"].split(":")[5])
            elif record.get("eventSource") == "aws:sqs":  # SQS
                self.source = "sqs"
                transaction_type = "messaging"
                transaction_name = "RECEIVE {}".format(
                    record["eventSourceARN"].split(":")[5])

        self.transaction = self.client.begin_transaction(
            transaction_type, trace_parent=trace_parent)
        elasticapm.set_transaction_name(transaction_name, override=False)
        if self.source == "api":
            elasticapm.set_context(
                lambda: get_data_from_request(
                    self.event,
                    capture_body=self.client.config.capture_body in
                    ("transactions", "all"),
                    capture_headers=self.client.config.capture_headers,
                ),
                "request",
            )
        self.set_metadata_and_context(cold_start)
Beispiel #13
0
 def request_started(self, app):
     if (not self.app.debug or self.client.config.debug) and not self.client.should_ignore_url(request.path):
         trace_parent = TraceParent.from_headers(request.headers)
         self.client.begin_transaction("request", trace_parent=trace_parent)
         elasticapm.set_context(
             lambda: get_data_from_request(request, self.client.config, constants.TRANSACTION), "request"
         )
         rule = request.url_rule.rule if request.url_rule is not None else ""
         rule = build_name_with_http_method_prefix(rule, request)
         elasticapm.set_transaction_name(rule, override=False)
Beispiel #14
0
def process_request_wrapper(wrapped, instance, args, kwargs):
    response = wrapped(*args, **kwargs)
    try:
        if response is not None:
            request = args[0]
            elasticapm.set_transaction_name(
                build_name_with_http_method_prefix(
                    get_name_from_middleware(wrapped, instance), request))
    finally:
        return response
Beispiel #15
0
    async def _request_started(self, request: Request):
        """Captures the begin of the request processing to APM.

        Args:
            request (Request)
        """
        trace_parent = TraceParent.from_headers(dict(request.headers))
        self.client.begin_transaction("request", trace_parent=trace_parent)

        await set_context(lambda: get_data_from_request(request, self.client.config, constants.TRANSACTION), "request")
        elasticapm.set_transaction_name("{} {}".format(request.method, request.url.path), override=False)
Beispiel #16
0
def orders(request):
    if request.method == 'POST':
        # set transaction name to post_order
        elasticapm.set_transaction_name('POST opbeans.views.post_order')
        return post_order(request)
    order_list = list(
        m.Order.objects.values('id', 'customer_id', 'customer__full_name',
                               'created_at')[:1000])
    for order_dict in order_list:
        order_dict['customer_name'] = order_dict.pop('customer__full_name')
    return JsonResponse(order_list, safe=False)
Beispiel #17
0
 def _setup_transaction_name(self, request: Request) -> None:
     """
     Method used to setup the transaction name using the provided callback or the default mode
     :param request: Incoming HTTP Request entity
     :return: None
     """
     if self._transaction_name_callback:
         name = self._transaction_name_callback(request)
     else:
         name = self._default_transaction_name_generator(request=request)
     if name:
         set_transaction_name(name, override=False)
 def on_finish(self):
     apm_elastic = self.settings.get("apm_elastic")
     name_trasaction = '{} {}'.format(self.request.method, self.get_url())
     status = self.get_status()
     result = 'HTTP {}xx'.format(status // 100)
     data_request = get_data_from_request(self.request)
     data_response = get_data_from_response(self)
     elasticapm.set_context(lambda: data_request, "request")
     elasticapm.set_context(lambda: data_response, "response")
     elasticapm.set_transaction_name(name_trasaction, override=False)
     elasticapm.set_transaction_result(result, override=False)
     apm_elastic.client.end_transaction()
Beispiel #19
0
def test_set_transaction_name(elasticapm_client):
    elasticapm_client.begin_transaction('test')
    elasticapm_client.end_transaction('test_name', 200)

    elasticapm_client.begin_transaction('test')

    elasticapm.set_transaction_name('another_name')

    elasticapm_client.end_transaction('test_name', 200)

    transactions = elasticapm_client.instrumentation_store.get_all()
    assert transactions[0]['name'] == 'test_name'
    assert transactions[1]['name'] == 'another_name'
Beispiel #20
0
def test_set_transaction_name(elasticapm_client):
    elasticapm_client.begin_transaction("test")
    elasticapm_client.end_transaction("test_name", 200)

    elasticapm_client.begin_transaction("test")

    elasticapm.set_transaction_name("another_name")

    elasticapm_client.end_transaction("test_name", 200)

    transactions = elasticapm_client.transaction_store.get_all()
    assert transactions[0]["name"] == "test_name"
    assert transactions[1]["name"] == "another_name"
Beispiel #21
0
def process_response_wrapper(wrapped, instance, args, kwargs):
    response = wrapped(*args, **kwargs)
    try:
        request, original_response = args
        # if there's no view_func on the request, and this middleware created
        # a new response object, it's logged as the responsible transaction
        # name
        if not hasattr(request, "_elasticapm_view_func") and response is not original_response:
            elasticapm.set_transaction_name(
                build_name_with_http_method_prefix(get_name_from_middleware(wrapped, instance), request)
            )
    finally:
        return response
Beispiel #22
0
def test_set_transaction_name(elasticapm_client):
    elasticapm_client.begin_transaction("test")
    elasticapm_client.end_transaction("test_name", 200)

    elasticapm_client.begin_transaction("test")

    elasticapm.set_transaction_name("another_name")

    elasticapm_client.end_transaction("test_name", 200)

    transactions = elasticapm_client.events[TRANSACTION]
    assert transactions[0]["name"] == "test_name"
    assert transactions[1]["name"] == "another_name"
Beispiel #23
0
def test_set_transaction_name(elasticapm_client, name1, name2, expected1,
                              expected2):
    elasticapm_client.begin_transaction("test")
    elasticapm_client.end_transaction(name1, 200)

    elasticapm_client.begin_transaction("test")

    elasticapm.set_transaction_name(name2)

    elasticapm_client.end_transaction(name1, 200)

    transactions = elasticapm_client.events[TRANSACTION]
    assert transactions[0]["name"] == expected1
    assert transactions[1]["name"] == expected2
Beispiel #24
0
def orders(request):
    if request.method == 'POST':
        # set transaction name to post_order
        elasticapm.set_transaction_name('POST opbeans.views.post_order')
        return post_order(request)
    order_list = list(m.Order.objects.all()[:1000])
    with elasticapm.capture_span("iterate_orders"):
        orders = [
            {"id": order.id,
             "customer_id": order.customer_id,
             "customer_name": order.customer.full_name,
             "created_at": order.created_at
             } for order in order_list
        ]
    return JsonResponse(orders, safe=False)
Beispiel #25
0
 def request_started(self, app):
     if not self.app.debug or self.client.config.debug:
         trace_parent = TraceParent.from_headers(request.headers)
         self.client.begin_transaction("request", trace_parent=trace_parent)
         elasticapm.set_context(
             lambda: get_data_from_request(
                 request,
                 capture_body=self.client.config.capture_body in
                 ("transactions", "all"),
                 capture_headers=self.client.config.capture_headers,
             ),
             "request",
         )
         rule = request.url_rule.rule if request.url_rule is not None else ""
         rule = build_name_with_http_method_prefix(rule, request)
         elasticapm.set_transaction_name(rule, override=False)
Beispiel #26
0
    def process_response(self, request, response):
        if django_settings.DEBUG and not self.client.config.debug:
            return response
        if request.META.get('HTTP_USER_AGENT') == 'mcod-heartbeat':
            return response
        try:
            if hasattr(response, "status_code"):
                try:
                    route = request.resolver_match.route
                except AttributeError:
                    route = request.path

                transaction_name = route_to_name(route,
                                                 prefix='admin',
                                                 method=request.method)
                if transaction_name:
                    elasticapm.set_transaction_name(transaction_name,
                                                    override=False)

                elasticapm.set_context(
                    lambda: self.client.get_data_from_request(
                        request,
                        capture_body=self.client.config.capture_body in
                        ("all", "transactions")),
                    "request",
                )
                elasticapm.set_context(
                    lambda: self.client.get_data_from_response(response),
                    "response")
                elasticapm.set_context(
                    lambda: self.client.get_user_info(request), "user")
                elasticapm.set_transaction_result("HTTP {}xx".format(
                    response.status_code // 100),
                                                  override=False)
        except Exception:
            self.client.error_logger.error(
                "Exception during timing of request", exc_info=True)
        return response
Beispiel #27
0
def override_transaction_name_view(request):
    elasticapm.set_transaction_name("foo")
    elasticapm.set_transaction_result("okydoky")
    return HttpResponse()
Beispiel #28
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        topic = None
        destination_info = {
            "service": {
                "name": "kafka",
                "resource": "kafka/",
                "type": "messaging"
            },
        }
        self.destination_info = destination_info
        if method == "KafkaProducer.send":
            address = None
            port = None
            time_start = time.time()
            while not instance._metadata.controller:
                if time.time() - time_start > 1:
                    break
                continue
            if instance:
                if instance._metadata.controller:
                    address = instance._metadata.controller[1]
                    port = instance._metadata.controller[2]
            self.destination_info["port"] = port
            self.destination_info["address"] = address
            topic = args[0].encode("utf-8")
            transaction = execution_context.get_transaction()
            if transaction:
                return self._trace_send(wrapped, topic, **kwargs)

        if method == "KafkaConsumer.next":
            transaction = execution_context.get_transaction()
            if transaction and transaction.transaction_type != "messaging":
                action = "consume"
                with capture_span(
                        name="consumer",
                        span_type="messaging",
                        span_subtype=self.provider_name,
                        span_action=action,
                        extra={
                            "message": {
                                "queue": {
                                    "name": ""
                                }
                            },
                            "destination": self.destination_info,
                        },
                ) as span:
                    result = wrapped(*args, **kwargs)
                    topic = result[0]
                    new_trace_id = get_trace_id(result)
                    service = self.destination_info["service"]
                    service["resource"] = service["resource"] + topic
                    span.context["message"]["queue"]["name"] = topic
                    span.context["destination"]["service"] = service
                    span.name = "KafkaConsumer#receive from " + topic
                    transaction.trace_parent = TraceParent.from_string(
                        new_trace_id)
                    return result
            else:
                client = get_client()
                if transaction and transaction.transaction_type == "messaging":
                    client.end_transaction()

                result = wrapped(*args, **kwargs)
                topic = result[0]
                new_trace_id = None
                new_trace_id = get_trace_id(result)

                client.begin_transaction("messaging", trace_parent=None)
                transaction = execution_context.get_transaction()
                if result.timestamp_type == 0:
                    current_time_millis = int(round(time.time() * 1000))
                    age = current_time_millis - result.timestamp
                    transaction.context = {
                        "message": {
                            "age": {
                                "ms": age
                            },
                            "queue": {
                                "name": topic
                            }
                        }
                    }
                if new_trace_id:
                    transaction.trace_parent = TraceParent.from_string(
                        new_trace_id)
                t_name = "Kafka record from " + topic
                elasticapm.set_transaction_name(t_name, override=True)
                res = constants.OUTCOME.SUCCESS
                elasticapm.set_transaction_result(res, override=False)
                return result
Beispiel #29
0
    async def handle_request(request, handler):
        elasticapm_client = get_client() if client is None else client
        should_trace = elasticapm_client and not elasticapm_client.should_ignore_url(
            request.path)
        if should_trace:
            trace_parent = AioHttpTraceParent.from_headers(request.headers)
            elasticapm_client.begin_transaction("request",
                                                trace_parent=trace_parent)
            resource = request.match_info.route.resource
            name = request.method
            if resource:
                # canonical has been added in 3.3, and returns one of path, formatter, prefix
                for attr in ("canonical", "_path", "_formatter", "_prefix"):
                    if hasattr(resource, attr):
                        name += " " + getattr(resource, attr)
                        break
                else:
                    name += " unknown route"
            else:
                name += " unknown route"
            elasticapm.set_transaction_name(name, override=False)
            elasticapm.set_context(
                lambda: get_data_from_request(request, elasticapm_client.
                                              config, constants.TRANSACTION),
                "request")

        try:
            response = await handler(request)
            if should_trace:
                elasticapm.set_transaction_result("HTTP {}xx".format(
                    response.status // 100),
                                                  override=False)
                elasticapm.set_transaction_outcome(
                    http_status_code=response.status, override=False)
                elasticapm.set_context(
                    lambda:
                    get_data_from_response(response, elasticapm_client.config,
                                           constants.TRANSACTION),
                    "response",
                )
            return response
        except HTTPException as exc:
            # HTTPExceptions are response-like, e.g. have headers and status code. They can represent an HTTP
            # response below a 500 status code and therefore not something to capture as exception. Like
            # HTTPOk can be raised but will most likely be wrongly tagged as an APM error. Let's try and
            # capture this according to the status.
            if exc.status_code < 500 and not should_trace:
                raise
            if elasticapm_client:
                elasticapm.set_transaction_result("HTTP {}xx".format(
                    exc.status_code // 100),
                                                  override=False)
                elasticapm.set_transaction_outcome(
                    http_status_code=exc.status_code, override=False)
                elasticapm.set_context(
                    lambda: get_data_from_response(
                        exc,  # noqa: F821
                        elasticapm_client.config,
                        constants.ERROR if exc.status_code >= 500 else
                        constants.TRANSACTION,  # noqa: F821
                    ),
                    "response",
                )
                if exc.status_code >= 500:
                    elasticapm_client.capture_exception(
                        context={
                            "request":
                            get_data_from_request(request, elasticapm_client.
                                                  config, constants.ERROR)
                        })
            raise
        except Exception:
            if elasticapm_client:
                elasticapm.set_transaction_result("HTTP 5xx", override=False)
                elasticapm.set_transaction_outcome(http_status_code=500,
                                                   override=False)
                elasticapm.set_context({"status_code": 500}, "response")
                elasticapm_client.capture_exception(
                    context={
                        "request":
                        get_data_from_request(
                            request, elasticapm_client.config, constants.ERROR)
                    })
            raise
        finally:
            elasticapm_client.end_transaction()
Beispiel #30
0
 def transaction_name():
     elasticapm.set_transaction_name("foo")
     elasticapm.set_transaction_result("okydoky")
     return Response("")