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
Ejemplo n.º 2
0
def get_trace_parent(celery_task):
    """
    Return a trace parent contained in the request headers of a Celery Task object or None
    """
    trace_parent = None
    with suppress(AttributeError, KeyError, TypeError):
        if celery_task.request.headers is not None:
            trace_parent_string = celery_task.request.headers["elasticapm"][
                "trace_parent_string"]
            trace_parent = TraceParent.from_string(trace_parent_string)
        else:
            trace_parent_string = celery_task.request.elasticapm[
                "trace_parent_string"]
            trace_parent = TraceParent.from_string(trace_parent_string)
    return trace_parent
Ejemplo n.º 3
0
def test_span_only_dropped(instrument, elasticapm_client, waiting_httpserver):
    """test that urllib instrumentation does not fail if no parent span can be found"""
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    transaction_object = elasticapm_client.begin_transaction("transaction")
    for i in range(2):
        with capture_span("test", "test"):
            urlopen(url)
    elasticapm_client.end_transaction("bla", "OK")
    trace_parent_1 = TraceParent.from_string(waiting_httpserver.requests[0].headers[constants.TRACEPARENT_HEADER_NAME])
    trace_parent_2 = TraceParent.from_string(waiting_httpserver.requests[1].headers[constants.TRACEPARENT_HEADER_NAME])

    assert trace_parent_1.span_id != transaction_object.id
    # second request should use transaction id as span id because there is no span
    assert trace_parent_2.span_id == transaction_object.id
Ejemplo n.º 4
0
def test_trace_parent_wrong_version_255(caplog):
    """Version FF or 255 is explicitly forbidden"""
    header = "ff-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-03"
    with caplog.at_level("DEBUG", "elasticapm.utils"):
        trace_parent = TraceParent.from_string(header)
    assert trace_parent is None
    assert_any_record_contains(caplog.records, "Invalid version field, value 255")
Ejemplo n.º 5
0
def test_httpx_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"):
        httpx.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"].startswith("GET 127.0.0.1:")
    assert spans[0]["type"] == "external"
    assert spans[0]["subtype"] == "http"
    assert url == spans[0]["context"]["http"]["url"]
    assert spans[0]["context"]["destination"]["service"] == {
        "name": "",
        "resource": "127.0.0.1:%d" % parsed_url.port,
        "type": "",
    }

    headers = waiting_httpserver.requests[0].headers
    assert constants.TRACEPARENT_HEADER_NAME in headers
    trace_parent = TraceParent.from_string(
        headers[constants.TRACEPARENT_HEADER_NAME], tracestate_string=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 `httpx`, not of httpcore
    assert trace_parent.span_id == spans[0]["id"]
    assert trace_parent.trace_options.recorded
Ejemplo n.º 6
0
def test_trace_parent_wrong_format(caplog):
    header = "00"
    with caplog.at_level("DEBUG", "elasticapm.utils"):
        trace_parent = TraceParent.from_string(header)
    record = caplog.records[0]
    assert trace_parent is None
    assert record.message == "Invalid traceparent header format, value 00"
Ejemplo n.º 7
0
async def test_trace_parent_propagation_unsampled(instrument, event_loop,
                                                  elasticapm_client,
                                                  waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    transaction_object = elasticapm_client.begin_transaction("transaction")
    transaction_object.is_sampled = False
    async with aiohttp.ClientSession() as session:
        async with session.get(waiting_httpserver.url) as resp:
            status = resp.status
            text = await resp.text()
    elasticapm_client.end_transaction("MyView")
    transactions = elasticapm_client.events[constants.TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    assert not spans

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

    if elasticapm_client.config.use_elastic_traceparent_header:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME in headers
        assert headers[constants.TRACEPARENT_HEADER_NAME] == headers[
            constants.TRACEPARENT_LEGACY_HEADER_NAME]
    else:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME not in headers
Ejemplo n.º 8
0
def test_trace_parent(elasticapm_client):
    trace_parent = TraceParent.from_string("00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-03")
    elasticapm_client.begin_transaction("test", trace_parent=trace_parent)
    transaction = elasticapm_client.end_transaction("test", "OK")
    data = transaction.to_dict()
    assert data["trace_id"] == "0af7651916cd43dd8448eb211c80319c"
    assert data["parent_id"] == "b7ad6b7169203331"
Ejemplo n.º 9
0
    def begin_transaction(self, transaction_type, trace_parent=None):
        """
        Start a new transactions and bind it in a thread-local variable

        :returns the Transaction object
        """
        if trace_parent:
            is_sampled = bool(trace_parent.trace_options.recorded)
        else:
            is_sampled = (
                self.config.transaction_sample_rate == 1.0
                or self.config.transaction_sample_rate > random.random())
        transaction = Transaction(self,
                                  transaction_type,
                                  trace_parent=trace_parent,
                                  is_sampled=is_sampled)
        if trace_parent is None:
            transaction.trace_parent = TraceParent(
                constants.TRACE_CONTEXT_VERSION,
                "%032x" % random.getrandbits(128),
                transaction.id,
                TracingOptions(recorded=is_sampled),
            )
        execution_context.set_transaction(transaction)
        return transaction
Ejemplo n.º 10
0
def test_get_trace_parent_header(elasticapm_client):
    trace_parent = TraceParent.from_string(
        "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-03")
    transaction = elasticapm_client.begin_transaction(
        "test", trace_parent=trace_parent)
    assert transaction.trace_parent.to_string(
    ) == elasticapm.get_trace_parent_header()
Ejemplo n.º 11
0
 def request_started(self, app):
     if not self.app.debug or self.client.config.debug:
         if constants.TRACEPARENT_HEADER_NAME in request.headers:
             trace_parent = TraceParent.from_string(request.headers[constants.TRACEPARENT_HEADER_NAME])
         else:
             trace_parent = None
         self.client.begin_transaction("request", trace_parent=trace_parent)
def test_trace_parent_wrong_trace_options_field(caplog):
    header = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-xx"
    with caplog.at_level("DEBUG", "elasticapm.utils"):
        trace_parent = TraceParent.from_string(header)
    assert trace_parent is None
    assert_any_record_contains(caplog.records,
                               "Invalid trace-options field, value xx")
def test_trace_parent_wrong_format(caplog):
    header = "00"
    with caplog.at_level("DEBUG", "elasticapm.utils"):
        trace_parent = TraceParent.from_string(header)
    assert trace_parent is None
    assert_any_record_contains(caplog.records,
                               "Invalid traceparent header format, value 00")
def test_httplib2_instrumentation(instrument, elasticapm_client,
                                  waiting_httpserver, args):
    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"):
        httplib2.Http().request(url, *args)
    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": "http://127.0.0.1:%d" % parsed_url.port,
        "resource": "127.0.0.1:%d" % parsed_url.port,
        "type": "external",
    }
    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
Ejemplo n.º 15
0
def test_trace_parent_propagation_unsampled(instrument, elasticapm_client,
                                            waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    transaction_object = elasticapm_client.begin_transaction("transaction")
    transaction_object.is_sampled = False
    urlopen(url)
    elasticapm_client.end_transaction("MyView")
    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    assert not spans

    headers = waiting_httpserver.requests[0].headers
    assert constants.TRACEPARENT_HEADER_NAME in headers
    trace_parent = TraceParent.from_string(
        headers[constants.TRACEPARENT_HEADER_NAME])
    assert trace_parent.trace_id == transactions[0]["trace_id"]
    assert trace_parent.span_id == transaction_object.id
    assert not trace_parent.trace_options.recorded

    if elasticapm_client.config.use_elastic_traceparent_header:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME in headers
        assert headers[constants.TRACEPARENT_HEADER_NAME] == headers[
            constants.TRACEPARENT_LEGACY_HEADER_NAME]
    else:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME not in headers
Ejemplo n.º 16
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
Ejemplo n.º 17
0
    def begin_transaction(self, transaction_type, trace_parent=None, start=None):
        """
        Start a new transactions and bind it in a thread-local variable

        :param transaction_type: type of the transaction, e.g. "request"
        :param trace_parent: an optional TraceParent object
        :param start: override the start timestamp, mostly useful for testing

        :returns the Transaction object
        """
        if trace_parent:
            is_sampled = bool(trace_parent.trace_options.recorded)
        else:
            is_sampled = (
                self.config.transaction_sample_rate == 1.0 or self.config.transaction_sample_rate > random.random()
            )
        transaction = Transaction(self, transaction_type, trace_parent=trace_parent, is_sampled=is_sampled, start=start)
        if trace_parent is None:
            transaction.trace_parent = TraceParent(
                constants.TRACE_CONTEXT_VERSION,
                "%032x" % random.getrandbits(128),
                transaction.id,
                TracingOptions(recorded=is_sampled),
            )
        execution_context.set_transaction(transaction)
        return transaction
Ejemplo n.º 18
0
def test_trace_parent_propagation_sampled(instrument, elasticapm_client,
                                          waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    elasticapm_client.begin_transaction("transaction")
    urlopen(url)
    elasticapm_client.end_transaction("MyView")
    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

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

    if elasticapm_client.config.use_elastic_traceparent_header:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME in headers
        assert headers[constants.TRACEPARENT_HEADER_NAME] == headers[
            constants.TRACEPARENT_LEGACY_HEADER_NAME]
    else:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME not in headers
Ejemplo n.º 19
0
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
Ejemplo n.º 20
0
def test_trace_parent_propagation_unsampled(instrument, elasticapm_client,
                                            waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    transaction_object = elasticapm_client.begin_transaction("transaction")
    transaction_object.is_sampled = False
    pool = urllib3.PoolManager(timeout=0.1)
    r = pool.request("GET", url)
    elasticapm_client.end_transaction("MyView")
    spans = elasticapm_client.events[SPAN]

    assert not spans

    headers = waiting_httpserver.requests[0].headers
    assert constants.TRACEPARENT_HEADER_NAME in headers
    trace_parent = TraceParent.from_string(
        headers[constants.TRACEPARENT_HEADER_NAME],
        tracestate_string=headers[constants.TRACESTATE_HEADER_NAME])
    assert trace_parent.trace_id == transaction_object.trace_parent.trace_id
    assert trace_parent.span_id == transaction_object.id
    assert not trace_parent.trace_options.recorded
    # Check that sample_rate was correctly placed in the tracestate
    assert constants.TRACESTATE.SAMPLE_RATE in trace_parent.tracestate_dict
    if elasticapm_client.config.use_elastic_traceparent_header:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME in headers
        assert headers[constants.TRACEPARENT_HEADER_NAME] == headers[
            constants.TRACEPARENT_LEGACY_HEADER_NAME]
    else:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME not in headers
Ejemplo n.º 21
0
async def test_httpx_instrumentation_string_url(instrument, elasticapm_client,
                                                waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    elasticapm_client.begin_transaction("transaction.test")
    async with async_capture_span("test_request", "test"):
        async with httpx.AsyncClient() as client:
            await client.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 url == spans[0]["context"]["http"]["url"]

    headers = waiting_httpserver.requests[0].headers
    assert constants.TRACEPARENT_HEADER_NAME in headers
    trace_parent = TraceParent.from_string(
        headers[constants.TRACEPARENT_HEADER_NAME],
        tracestate_string=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 `httpx`, not of urllib3
    assert trace_parent.span_id == spans[0]["id"]
    assert trace_parent.trace_options.recorded
Ejemplo n.º 22
0
def test_trace_parent_propagation_sampled(instrument, elasticapm_client,
                                          waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    elasticapm_client.begin_transaction("transaction")
    pool = urllib3.PoolManager(timeout=0.1)
    r = pool.request("GET", url)
    elasticapm_client.end_transaction("MyView")
    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

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

    if elasticapm_client.config.use_elastic_traceparent_header:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME in headers
        assert headers[constants.TRACEPARENT_HEADER_NAME] == headers[
            constants.TRACEPARENT_LEGACY_HEADER_NAME]
    else:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME not in headers
Ejemplo n.º 23
0
async def test_trace_parent_propagation_sampled(instrument, event_loop,
                                                elasticapm_client,
                                                waiting_httpserver):
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    elasticapm_client.begin_transaction("transaction")
    async with aiohttp.ClientSession() as session:
        async with session.get(waiting_httpserver.url) as resp:
            status = resp.status
            text = await resp.text()
    elasticapm_client.end_transaction("MyView")
    transactions = elasticapm_client.events[constants.TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

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

    if elasticapm_client.config.use_elastic_traceparent_header:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME in headers
        assert headers[constants.TRACEPARENT_HEADER_NAME] == headers[
            constants.TRACEPARENT_LEGACY_HEADER_NAME]
    else:
        assert constants.TRACEPARENT_LEGACY_HEADER_NAME not in headers
Ejemplo n.º 24
0
def test_trace_parent_wrong_version(caplog):
    header = "xx-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-03"
    with caplog.at_level("DEBUG", "elasticapm.utils"):
        trace_parent = TraceParent.from_string(header)
    record = caplog.records[0]
    assert trace_parent is None
    assert record.message == "Invalid version field, value xx"
Ejemplo n.º 25
0
def test_tracer_inject_map(tracer):
    span_context = OTSpanContext(trace_parent=TraceParent.from_string(
        "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"))
    carrier = {}
    tracer.inject(span_context, Format.TEXT_MAP, carrier)
    assert carrier[
        "elastic-apm-traceparent"] == b"00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
Ejemplo n.º 26
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
Ejemplo n.º 27
0
async def test_trace_parent_propagation_sampled_headers_none(
        instrument, event_loop, elasticapm_client, waiting_httpserver,
        sampled):
    """
    Test that we don't blow up if headers are explicitly set to None
    """
    waiting_httpserver.serve_content("")
    url = waiting_httpserver.url + "/hello_world"
    transaction = elasticapm_client.begin_transaction("transaction")
    transaction.is_sampled = sampled
    async with aiohttp.ClientSession() as session:
        async with session.get(waiting_httpserver.url, headers=None) as resp:
            status = resp.status
            text = await resp.text()
    elasticapm_client.end_transaction("MyView")
    transactions = elasticapm_client.events[constants.TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])

    headers = waiting_httpserver.requests[0].headers
    assert constants.TRACEPARENT_HEADER_NAME in headers
    trace_parent = TraceParent.from_string(
        headers[constants.TRACEPARENT_HEADER_NAME],
        tracestate_string=headers[constants.TRACESTATE_HEADER_NAME])
    assert trace_parent.trace_id == transactions[0]["trace_id"]
    if sampled:
        assert trace_parent.span_id == spans[0]["id"]
    else:
        assert trace_parent.tracestate_dict[
            constants.TRACESTATE.SAMPLE_RATE] == "0"
        assert trace_parent.span_id == transactions[0]["id"]
Ejemplo n.º 28
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)
Ejemplo n.º 29
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)
Ejemplo n.º 30
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 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 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