Example #1
0
 def call(self, module, method, wrapped, instance, args, kwargs):
     cls_name, method_name = method.split(".", 1)
     signature = ".".join([instance.full_name, method_name])
     host, port = instance.database.client.address
     destination_info = {
         "address": host,
         "port": port,
         "service": {
             "name": "mongodb",
             "resource": "mongodb",
             "type": "db"
         },
     }
     with capture_span(
             signature,
             span_type="db",
             span_subtype="mongodb",
             span_action="query",
             leaf=True,
             extra={"destination": destination_info},
     ):
         return wrapped(*args, **kwargs)
Example #2
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        if "operation_name" in kwargs:
            operation_name = kwargs["operation_name"]
        else:
            operation_name = args[0]

        target_endpoint = instance._endpoint.host
        parsed_url = urlparse.urlparse(target_endpoint)
        if "." in parsed_url.hostname:
            service, region = parsed_url.hostname.split(".", 2)[:2]
        else:
            service, region = parsed_url.hostname, None

        signature = "{}:{}".format(service, operation_name)
        extra_data = {
            "service": service,
            "region": region,
            "operation": operation_name
        }

        with capture_span(signature, "ext.http.aws", extra_data, leaf=True):
            return wrapped(*args, **kwargs)
Example #3
0
 def _trace_sql(self, method, sql, params, action=QUERY_ACTION):
     sql_string = self._bake_sql(sql)
     if action == EXEC_ACTION:
         signature = sql_string + "()"
     else:
         signature = self.extract_signature(sql_string)
     with capture_span(
         signature,
         span_type="db",
         span_subtype=self.provider_name,
         span_action=action,
         extra={"db": {"type": "sql", "statement": sql_string}, "destination": self._self_destination_info},
         skip_frames=1,
     ) as span:
         if params is None:
             result = method(sql)
         else:
             result = method(sql, params)
         # store "rows affected", but only for DML queries like insert/update/delete
         if span and self.rowcount not in (-1, None) and signature.startswith(self.DML_QUERIES):
             span.update_context("db", {"rows_affected": self.rowcount})
         return result
Example #4
0
def test_requests_instrumentation(instrument, elasticapm_client,
                                  waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    parsed_url = compat.urlparse.urlparse(url)
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_request", "test"):
        requests.get(url, allow_redirects=False)
    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])
    assert spans[0]["name"].startswith("GET 127.0.0.1:")
    assert spans[0]["type"] == "external"
    assert spans[0]["subtype"] == "http"
    assert url == spans[0]["context"]["http"]["url"]
    assert 200 == spans[0]["context"]["http"]["status_code"]
    assert spans[0]["context"]["destination"]["service"] == {
        "name": "",
        "resource": "127.0.0.1:%d" % parsed_url.port,
        "type": "",
    }
    assert spans[0]["outcome"] == "success"

    assert constants.TRACEPARENT_HEADER_NAME in waiting_httpserver.requests[
        0].headers
    trace_parent = TraceParent.from_string(
        waiting_httpserver.requests[0].headers[
            constants.TRACEPARENT_HEADER_NAME],
        tracestate_string=waiting_httpserver.requests[0].headers[
            constants.TRACESTATE_HEADER_NAME],
    )
    assert trace_parent.trace_id == transactions[0]["trace_id"]
    # Check that sample_rate was correctly placed in the tracestate
    assert constants.TRACESTATE.SAMPLE_RATE in trace_parent.tracestate_dict

    # this should be the span id of `requests`, not of urllib3
    assert trace_parent.span_id == spans[0]["id"]
    assert trace_parent.trace_options.recorded
Example #5
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        if 'operation_name' in kwargs:
            operation_name = kwargs['operation_name']
        else:
            operation_name = args[0]

        target_endpoint = instance._endpoint.host
        parsed_url = urlparse.urlparse(target_endpoint)
        if '.' in parsed_url.hostname:
            service, region = parsed_url.hostname.split('.', 2)[:2]
        else:
            service, region = parsed_url.hostname, None

        signature = '{}:{}'.format(service, operation_name)
        extra_data = {
            'service': service,
            'region': region,
            'operation': operation_name,
        }

        with capture_span(signature, 'ext.http.aws', extra_data, leaf=True):
            return wrapped(*args, **kwargs)
Example #6
0
 def call(self, module, method, wrapped, instance, args, kwargs):
     name = self.get_wrapped_name(wrapped, instance, method)
     address, port = None, None
     if instance.servers:
         first_server = instance.servers[0]
         if first_server.family == socket.AF_UNIX:
             address = first_server.address
         else:
             address, port = first_server.address
     destination = {
         "address": address,
         "port": port,
     }
     with capture_span(
             name,
             span_type="cache",
             span_subtype="memcached",
             span_action="query",
             extra={"destination": destination},
             leaf=True,
     ):
         return wrapped(*args, **kwargs)
def test_requests_instrumentation_error(instrument, elasticapm_client, waiting_httpserver, status_code):
    waiting_httpserver.serve_content("", code=status_code)
    url = waiting_httpserver.url + "/hello_world"
    parsed_url = compat.urlparse.urlparse(url)
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_request", "test"):
        requests.get(url, allow_redirects=False)
    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])
    assert spans[0]["name"].startswith("GET 127.0.0.1:")
    assert spans[0]["type"] == "external"
    assert spans[0]["subtype"] == "http"
    assert url == spans[0]["context"]["http"]["url"]
    assert status_code == spans[0]["context"]["http"]["status_code"]
    assert spans[0]["context"]["destination"]["service"] == {
        "name": "http://127.0.0.1:%d" % parsed_url.port,
        "resource": "127.0.0.1:%d" % parsed_url.port,
        "type": "external",
    }
    assert spans[0]["outcome"] == "failure"
Example #8
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        name = self.get_wrapped_name(wrapped, instance, method)
        context = None
        if method == "Cluster.connect":
            span_type = "db.cassandra.connect"
        else:
            span_type = "db.cassandra.query"
            query = args[0] if args else kwargs.get("query")
            if hasattr(query, "query_string"):
                query_str = query.query_string
            elif hasattr(query, "prepared_statement") and hasattr(query.prepared_statement, "query"):
                query_str = query.prepared_statement.query
            elif isinstance(query, compat.string_types):
                query_str = query
            else:
                query_str = None
            if query_str:
                name = extract_signature(query_str)
                context = {"db": {"type": "sql", "statement": query_str}}

        with capture_span(name, span_type, context):
            return wrapped(*args, **kwargs)
Example #9
0
def test_pylibmc(instrument, elasticapm_client):
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_memcached", "test"):
        host = os.environ.get("MEMCACHED_HOST", "localhost")
        conn = pylibmc.Client([host + ":11211"])
        conn.set("mykey", "a")
        assert "a" == conn.get("mykey")
        assert {"mykey": "a"} == conn.get_multi(["mykey", "myotherkey"])
    elasticapm_client.end_transaction("BillingView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    expected_signatures = {"test_memcached", "Client.set", "Client.get", "Client.get_multi"}

    assert {t["name"] for t in spans} == expected_signatures

    assert spans[0]["name"] == "Client.set"
    assert spans[0]["type"] == "cache"
    assert spans[0]["subtype"] == "memcached"
    assert spans[0]["action"] == "query"
    assert spans[0]["parent_id"] == spans[3]["id"]

    assert spans[1]["name"] == "Client.get"
    assert spans[1]["type"] == "cache"
    assert spans[1]["subtype"] == "memcached"
    assert spans[1]["action"] == "query"
    assert spans[1]["parent_id"] == spans[3]["id"]

    assert spans[2]["name"] == "Client.get_multi"
    assert spans[2]["type"] == "cache"
    assert spans[2]["subtype"] == "memcached"
    assert spans[2]["action"] == "query"
    assert spans[2]["parent_id"] == spans[3]["id"]

    assert spans[3]["name"] == "test_memcached"
    assert spans[3]["type"] == "test"

    assert len(spans) == 4
Example #10
0
def test_urllib3(instrument, elasticapm_client, waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    parsed_url = urlparse.urlparse(url)
    elasticapm_client.begin_transaction("transaction")
    expected_sig = "GET {0}".format(parsed_url.netloc)
    with capture_span("test_name", "test_type"):
        pool = urllib3.PoolManager(timeout=0.1)

        url = "http://{0}/hello_world".format(parsed_url.netloc)
        r = pool.request("GET", url)

    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    expected_signatures = {"test_name", expected_sig}

    assert {t["name"] for t in spans} == expected_signatures

    assert len(spans) == 2

    assert spans[0]["name"] == expected_sig
    assert spans[0]["type"] == "external"
    assert spans[0]["subtype"] == "http"
    assert spans[0]["context"]["http"]["url"] == url
    assert spans[0]["context"]["http"]["status_code"] == 200
    assert spans[0]["context"]["destination"]["service"] == {
        "name": "",
        "resource": "127.0.0.1:%d" % parsed_url.port,
        "type": "",
    }
    assert spans[0]["parent_id"] == spans[1]["id"]
    assert spans[0]["outcome"] == "success"

    assert spans[1]["name"] == "test_name"
    assert spans[1]["type"] == "test_type"
    assert spans[1]["parent_id"] == transactions[0]["id"]
Example #11
0
def test_httpx_error(instrument, elasticapm_client, waiting_httpserver, status_code):
    waiting_httpserver.serve_content("", code=status_code)
    url = waiting_httpserver.url + "/hello_world"
    parsed_url = compat.urlparse.urlparse(url)
    elasticapm_client.begin_transaction("transaction")
    expected_sig = "GET {0}".format(parsed_url.netloc)
    url = "http://{0}/hello_world".format(parsed_url.netloc)
    with capture_span("test_name", "test_type"):
        c = httpx.Client()
        c.get(url, **allow_redirects)

    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    assert spans[0]["name"] == expected_sig
    assert spans[0]["type"] == "external"
    assert spans[0]["subtype"] == "http"
    assert spans[0]["context"]["http"]["url"] == url
    assert spans[0]["context"]["http"]["status_code"] == status_code
    assert spans[0]["outcome"] == "failure"
    def call(self, module, method, wrapped, instance, args, kwargs):
        args, kwargs, params = self._ensure_headers_in_kwargs(args, kwargs)

        signature = params.get("method", "GET").upper()
        signature += " " + get_host_from_url(params["url"])
        url = sanitize_url(params["url"])
        destination = url_to_destination(url)
        transaction = execution_context.get_transaction()
        with capture_span(
                signature,
                span_type="external",
                span_subtype="http",
                extra={
                    "http": {
                        "url": url
                    },
                    "destination": destination
                },
                leaf=True,
        ) as span:
            # if httplib2 has been called in a leaf span, this span might be a DroppedSpan.
            leaf_span = span
            while isinstance(leaf_span, DroppedSpan):
                leaf_span = leaf_span.parent

            # It's possible that there are only dropped spans, e.g. if we started dropping spans.
            # In this case, the transaction.id is used
            parent_id = leaf_span.id if leaf_span else transaction.id
            trace_parent = transaction.trace_parent.copy_from(
                span_id=parent_id, trace_options=TracingOptions(recorded=True))
            self._set_disttracing_headers(params["headers"], trace_parent,
                                          transaction)

            response, content = wrapped(*args, **kwargs)
            if span.context:
                span.context["http"]["status_code"] = response.status
            span.set_success() if response.status < 400 else span.set_failure()
            return response, content
Example #13
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        name = "GraphQL"

        info = ""
        query = args[2]

        if "ResolveInfo" == type(query).__name__:
            if str(query.return_type) in [
                    "Boolean",
                    "Context",
                    "Date",
                    "DateTime",
                    "Decimal",
                    "Dynamic",
                    "Float",
                    "ID",
                    "Int",
                    "String",
                    "Time",
                    "UUID",
                    "Boolean",
                    "String",
            ]:
                return wrapped(*args, **kwargs)

            op = query.operation.operation
            field = query.field_name
            info = "%s %s" % (op, field)
        elif "RequestParams" == type(query).__name__:
            info = "%s %s" % ("request", query.query)
        else:
            info = str(query)

        with capture_span("%s.%s" % (name, info),
                          span_type="external",
                          span_subtype="graphql",
                          span_action="query"):
            return wrapped(*args, **kwargs)
Example #14
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        if "operation_name" in kwargs:
            operation_name = kwargs["operation_name"]
        else:
            operation_name = args[0]

        service_model = instance.meta.service_model
        if hasattr(service_model, "service_id"):  # added in boto3 1.7
            service = service_model.service_id
        else:
            service = service_model.service_name.upper()
            service = endpoint_to_service_id.get(service, service)

        parsed_url = urlparse.urlparse(instance.meta.endpoint_url)
        context = {
            "destination": {
                "address": parsed_url.hostname,
                "port": parsed_url.port,
                "cloud": {"region": instance.meta.region_name},
            }
        }

        handler_info = None
        handler = handlers.get(service, False)
        if handler:
            handler_info = handler(operation_name, service, instance, args, kwargs, context)
        if not handler_info:
            handler_info = handle_default(operation_name, service, instance, args, kwargs, context)

        with capture_span(
            handler_info.signature,
            span_type=handler_info.span_type,
            leaf=True,
            span_subtype=handler_info.span_subtype,
            span_action=handler_info.span_action,
            extra=handler_info.context,
        ):
            return wrapped(*args, **kwargs)
Example #15
0
def test_pymemcache_pooled_client(instrument, elasticapm_client):
    elasticapm_client.begin_transaction("transaction.test")
    host = os.environ.get("MEMCACHED_HOST", "localhost")
    with capture_span("test_pymemcache", "test"):
        conn = pymemcache.client.base.PooledClient((host, 11211))
        conn.set("mykey", "a")
        assert b"a" == conn.get("mykey")
        assert {"mykey": b"a"} == conn.get_many(["mykey", "myotherkey"])
    elasticapm_client.end_transaction("BillingView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    expected_signatures = {
        "test_pymemcache",
        "PooledClient.set",
        "PooledClient.get",
        "PooledClient.get_many",
    }

    assert {t["name"] for t in spans} == expected_signatures

    assert len(spans) == 4
Example #16
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        request_object = args[1] if len(args) > 1 else kwargs["req"]

        method = request_object.get_method()
        host = request_host(request_object)

        url = sanitize_url(request_object.get_full_url())
        signature = method.upper() + " " + host

        transaction = execution_context.get_transaction()

        with capture_span(signature, "ext.http.urllib", {"http": {"url": url}}, leaf=True) as span:
            # if urllib has been called in a leaf span, this span might be a DroppedSpan.
            leaf_span = span
            while isinstance(leaf_span, DroppedSpan):
                leaf_span = leaf_span.parent

            parent_id = leaf_span.id if leaf_span else transaction.id
            trace_parent = transaction.trace_parent.copy_from(
                span_id=parent_id, trace_options=TracingOptions(recorded=True)
            )
            request_object.add_header(constants.TRACEPARENT_HEADER_NAME, trace_parent.to_string())
            return wrapped(*args, **kwargs)
Example #17
0
 def call(self, module, method, wrapped, instance, args, kwargs):
     # pylint: disable=too-many-arguments
     """Wrapped method call"""
     view = kwargs.get('view')
     context = kwargs.get('context')
     with capture_span('RENDER',
                       span_type='template',
                       span_subtype='chameleon',
                       span_action='render',
                       labels={
                           'view':
                           '{}.{}'.format(view.__class__.__module__,
                                          view.__class__.__name__)
                           if view is not None else None,
                           'context':
                           '{}.{}'.format(context.__class__.__module__,
                                          context.__class__.__name__)
                           if context is not None else None,
                           'filename':
                           instance.filename
                       },
                       leaf=False):
         return wrapped(*args, **kwargs)
Example #18
0
def test_pipeline(instrument, elasticapm_client, redis_conn):
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_pipeline", "test"):
        pipeline = redis_conn.pipeline()
        pipeline.rpush("mykey", "a", "b")
        pipeline.expire("mykey", 1000)
        pipeline.execute()
    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    expected_signatures = {"test_pipeline", "StrictPipeline.execute"}

    assert {t["name"] for t in spans} == expected_signatures

    assert spans[0]["name"] == "StrictPipeline.execute"
    assert spans[0]["type"] == "cache.redis"

    assert spans[1]["name"] == "test_pipeline"
    assert spans[1]["type"] == "test"

    assert len(spans) == 2
def test_requests_instrumentation_via_prepared_request(instrument, elasticapm_client, waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_request", "test"):
        r = requests.Request("get", url)
        pr = r.prepare()
        s = requests.Session()
        s.send(pr, allow_redirects=False)
    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])
    assert spans[0]["name"].startswith("GET 127.0.0.1:")
    assert url == spans[0]["context"]["http"]["url"]

    assert constants.TRACEPARENT_HEADER_NAME in waiting_httpserver.requests[0].headers
    trace_parent = TraceParent.from_string(waiting_httpserver.requests[0].headers[constants.TRACEPARENT_HEADER_NAME])
    assert trace_parent.trace_id == transactions[0]["trace_id"]

    # this should be the span id of `requests`, not of urllib3
    assert trace_parent.span_id == spans[0]["id"]
    assert trace_parent.trace_options.recorded
Example #20
0
def test_rq_patches_redis(instrument, elasticapm_client, redis_conn):
    # Let's go ahead and change how something important works
    redis_conn._pipeline = partial(StrictRedis.pipeline, redis_conn)

    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_pipeline", "test"):
        # conn = redis.StrictRedis()
        pipeline = redis_conn._pipeline()
        pipeline.rpush("mykey", "a", "b")
        pipeline.expire("mykey", 1000)
        pipeline.execute()
    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    assert spans[0]["name"] in ("StrictPipeline.execute", "Pipeline.execute")
    assert spans[0]["type"] == "cache.redis"

    assert spans[1]["name"] == "test_pipeline"
    assert spans[1]["type"] == "test"

    assert len(spans) == 2
Example #21
0
def test_pipeline(elasticapm_client, redis_conn):
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_pipeline", "test"):
        pipeline = redis_conn.pipeline()
        pipeline.rpush("mykey", "a", "b")
        pipeline.expire("mykey", 1000)
        pipeline.execute()
    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.instrumentation_store.get_all()
    spans = transactions[0]['spans']

    expected_signatures = {'test_pipeline', 'StrictPipeline.execute'}

    assert {t['name'] for t in spans} == expected_signatures

    assert spans[0]['name'] == 'StrictPipeline.execute'
    assert spans[0]['type'] == 'cache.redis'

    assert spans[1]['name'] == 'test_pipeline'
    assert spans[1]['type'] == 'test'

    assert len(spans) == 2
Example #22
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        if "request" in kwargs:
            request = kwargs["request"]
        else:
            request = args[0]

        signature = request.method.upper()
        signature += " " + get_host_from_url(request.url)
        url = sanitize_url(request.url)

        with capture_span(
            signature,
            span_type="external",
            span_subtype="http",
            extra={"http": {"url": url}},
            leaf=True,
        ) as span:
            response = wrapped(*args, **kwargs)
            # requests.Response objects are falsy if status code > 400, so we have to check for None instead
            if response is not None:
                if span.context:
                    span.context["http"]["status_code"] = response.status_code
                span.set_success() if response.status_code < 400 else span.set_failure()
            return response
Example #23
0
def test_redis_client(instrument, elasticapm_client, redis_conn):
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_redis_client", "test"):
        redis_conn.rpush("mykey", "a", "b")
        redis_conn.expire("mykey", 1000)
    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    expected_signatures = {"test_redis_client", "RPUSH", "EXPIRE"}

    assert {t["name"] for t in spans} == expected_signatures

    assert spans[0]["name"] == "RPUSH"
    assert spans[0]["type"] == "cache.redis"

    assert spans[1]["name"] == "EXPIRE"
    assert spans[1]["type"] == "cache.redis"

    assert spans[2]["name"] == "test_redis_client"
    assert spans[2]["type"] == "test"

    assert len(spans) == 3
Example #24
0
def test_redis_client(elasticapm_client, redis_conn):
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_redis_client", "test"):
        redis_conn.rpush("mykey", "a", "b")
        redis_conn.expire("mykey", 1000)
    elasticapm_client.end_transaction("MyView")

    transactions = elasticapm_client.instrumentation_store.get_all()
    spans = transactions[0]['spans']

    expected_signatures = {'test_redis_client', 'RPUSH', 'EXPIRE'}

    assert {t['name'] for t in spans} == expected_signatures

    assert spans[0]['name'] == 'RPUSH'
    assert spans[0]['type'] == 'cache.redis'

    assert spans[1]['name'] == 'EXPIRE'
    assert spans[1]['type'] == 'cache.redis'

    assert spans[2]['name'] == 'test_redis_client'
    assert spans[2]['type'] == 'test'

    assert len(spans) == 3
Example #25
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        if "method" in kwargs:
            method = kwargs["method"]
        else:
            method = args[0]

        host = instance.host

        if instance.port != default_ports.get(instance.scheme):
            host += ":" + str(instance.port)

        if "url" in kwargs:
            url = kwargs["url"]
        else:
            url = args[1]

        signature = method.upper() + " " + host

        url = instance.scheme + "://" + host + url

        with capture_span(signature,
                          "ext.http.urllib3", {"url": url},
                          leaf=True):
            return wrapped(*args, **kwargs)
Example #26
0
 def call(self, module, method, wrapped, instance, args, kwargs):
     wrapped_name = self.get_wrapped_name(wrapped, instance, method)
     with capture_span(wrapped_name, "cache.redis", leaf=True):
         return wrapped(*args, **kwargs)
Example #27
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        name = self.get_wrapped_name(wrapped, instance, method)

        with capture_span(name, "cache.memcached"):
            return wrapped(*args, **kwargs)
Example #28
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        if "method" in kwargs:
            method = kwargs["method"].decode("utf-8")
        else:
            method = args[0].decode("utf-8")

        # URL is a tuple of (scheme, host, port, path), we want path
        if "url" in kwargs:
            url = kwargs["url"][3].decode("utf-8")
        else:
            url = args[1][3].decode("utf-8")

        headers = None
        if "headers" in kwargs:
            headers = kwargs["headers"]
            if headers is None:
                headers = []
                kwargs["headers"] = headers

        scheme, host, port = instance.origin
        scheme = scheme.decode("utf-8")
        host = host.decode("utf-8")

        if port != default_ports.get(scheme):
            host += ":" + str(port)

        signature = "%s %s" % (method.upper(), host)

        url = "%s://%s%s" % (scheme, host, url)
        destination = url_to_destination(url)

        transaction = execution_context.get_transaction()

        with capture_span(
                signature,
                span_type="external",
                span_subtype="http",
                extra={
                    "http": {
                        "url": url
                    },
                    "destination": destination
                },
                leaf=True,
        ) as span:
            # if httpcore has been called in a leaf span, this span might be a DroppedSpan.
            leaf_span = span
            while isinstance(leaf_span, DroppedSpan):
                leaf_span = leaf_span.parent

            if headers is not None:
                # It's possible that there are only dropped spans, e.g. if we started dropping spans.
                # In this case, the transaction.id is used
                parent_id = leaf_span.id if leaf_span else transaction.id
                trace_parent = transaction.trace_parent.copy_from(
                    span_id=parent_id,
                    trace_options=TracingOptions(recorded=True))
                self._set_disttracing_headers(headers, trace_parent,
                                              transaction)
            response = wrapped(*args, **kwargs)
            if len(response) > 4:
                # httpcore < 0.11.0
                # response = (http_version, status_code, reason_phrase, headers, stream)
                status_code = response[1]
            else:
                # httpcore >= 0.11.0
                # response = (status_code, headers, stream, ext)
                status_code = response[0]
            if status_code:
                if span.context:
                    span.context["http"]["status_code"] = status_code
                span.set_success() if status_code < 400 else span.set_failure()
            return response
def test_requests_instrumentation_malformed_path(instrument,
                                                 elasticapm_client):
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_request", "test"):
        with pytest.raises(InvalidURL):
            requests.get("http://")
def test_requests_instrumentation_malformed_schema(instrument,
                                                   elasticapm_client):
    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_request", "test"):
        with pytest.raises(MissingSchema):
            requests.get("")