def test_traceparent_from_header():
    header = "00-0000651916cd43dd8448eb211c80319c-b7ad6b7169203331-03"
    legacy_header = "00-1111651916cd43dd8448eb211c80319c-b7ad6b7169203331-03"
    tp1 = TraceParent.from_headers({"traceparent": header})
    tp2 = TraceParent.from_headers({"elastic-apm-traceparent": legacy_header})
    tp3 = TraceParent.from_headers({
        "traceparent": header,
        "elastic-apm-traceparent": legacy_header
    })
    assert tp1.to_string() == header
    assert tp2.to_string() == legacy_header
    # traceparent has precedence over elastic-apm-traceparent
    assert tp3.to_string() == header
Example #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)
Example #3
0
def _request_started_handler(client, sender, *args, **kwargs):
    if not _should_start_transaction(client):
        return
    # try to find trace id
    if "environ" in kwargs:
        trace_parent = TraceParent.from_headers(
            kwargs["environ"],
            TRACEPARENT_HEADER_NAME_WSGI,
            TRACEPARENT_LEGACY_HEADER_NAME_WSGI,
            TRACESTATE_HEADER_NAME_WSGI,
        )
    elif "scope" in kwargs and "headers" in kwargs["scope"]:
        trace_parent = TraceParent.from_headers(kwargs["scope"]["headers"])
    else:
        trace_parent = None
    client.begin_transaction("request", trace_parent=trace_parent)
Example #4
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
Example #5
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
Example #6
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)
Example #7
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)
Example #8
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)
Example #9
0
def _request_started_handler(client, sender, *args, **kwargs):
    if not _should_start_transaction(client):
        return
    # try to find trace id
    trace_parent = None
    if "environ" in kwargs:
        url = get_current_url(kwargs["environ"],
                              strip_querystring=True,
                              path_only=True)
        if client.should_ignore_url(url):
            logger.debug(
                "Ignoring request due to %s matching transaction_ignore_urls")
            return
        trace_parent = TraceParent.from_headers(
            kwargs["environ"],
            TRACEPARENT_HEADER_NAME_WSGI,
            TRACEPARENT_LEGACY_HEADER_NAME_WSGI,
            TRACESTATE_HEADER_NAME_WSGI,
        )
    elif "scope" in kwargs:
        scope = kwargs["scope"]
        fake_environ = {
            "SCRIPT_NAME": scope.get("root_path", ""),
            "PATH_INFO": scope["path"],
            "QUERY_STRING": ""
        }
        url = get_current_url(fake_environ,
                              strip_querystring=True,
                              path_only=True)
        if client.should_ignore_url(url):
            logger.debug(
                "Ignoring request due to %s matching transaction_ignore_urls")
            return
        if "headers" in scope:
            trace_parent = TraceParent.from_headers(scope["headers"])
    client.begin_transaction("request", trace_parent=trace_parent)
Example #10
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)
Example #11
0
        async def _instrument_request(request: Request):
            if not self._client.should_ignore_url(url=request.path):
                trace_parent = TraceParent.from_headers(headers=request.headers)
                self._client.begin_transaction("request", trace_parent=trace_parent)
                await set_context(
                    lambda: get_request_info(config=self._client.config, request=request),
                    "request",
                )
                self._setup_transaction_name(request=request)
                if self._user_context_callback:
                    name, email, uid = await self._user_context_callback(request)
                    set_user_context(username=name, email=email, user_id=uid)

                await self._setup_custom_context(request=request)

                if self._label_info_callback:
                    labels = await self._label_info_callback(request)
                    label(**labels)