def test_distributed_tracing_propagation_async(self):
        @self.app.task
        def fn_task():
            return 42

        # This header manipulation is copying the work that should be done
        # by the before_publish signal. Rip it out if Celery ever fixes their bug.
        current_context = Pin.get_from(
            self.app).tracer.context_provider.active()
        headers = {}
        HTTPPropagator.inject(current_context, headers)

        with self.override_config("celery", dict(distributed_tracing=True)):
            result = fn_task.apply_async(headers=headers)
            assert result.get(timeout=self.ASYNC_GET_TIMEOUT) == 42

        traces = self.pop_traces()

        if self.ASYNC_USE_CELERY_FIXTURES:
            assert 2 == len(traces)
            assert 1 == len(traces[0])
            assert 1 == len(traces[1])
            async_span = traces[0][0]
            run_span = traces[1][0]
            assert async_span.trace_id == 12345
        else:
            assert 1 == len(traces)
            assert 1 == len(traces[0])
            run_span = traces[0][0]

        assert run_span.trace_id == 12345
 def __init__(self, base_url):
     # type: (str) -> None
     self._base_url = base_url
     self._session = requests.Session()
     # Propagate traces with trace_id = 1 for the ping trace so we can filter them out.
     c, d = Context(trace_id=1, span_id=1), {}
     HTTPPropagator.inject(c, d)
     self._ignore_headers = d
Exemple #3
0
def _init_span(span, request):
    # type: (Span, httpx.Request) -> None
    span.set_tag(SPAN_MEASURED_KEY)

    if distributed_tracing_enabled(config.httpx):
        HTTPPropagator.inject(span.context, request.headers)

    sample_rate = config.httpx.get_analytics_sample_rate(use_global_config=True)
    if sample_rate is not None:
        span.set_tag(ANALYTICS_SAMPLE_RATE_KEY, sample_rate)
Exemple #4
0
    def test_inject(self):
        tracer = get_dummy_tracer()

        with tracer.trace("global_root_span") as span:
            headers = {}
            propagator = HTTPPropagator()
            propagator.inject(span.context, headers)

            eq_(int(headers[HTTP_HEADER_TRACE_ID]), span.trace_id)
            eq_(int(headers[HTTP_HEADER_PARENT_ID]), span.span_id)
Exemple #5
0
    def test_inject(self):
        tracer = get_dummy_tracer()

        with tracer.trace("global_root_span") as span:
            headers = {}
            propagator = HTTPPropagator()
            propagator.inject(span.context, headers)

            eq_(int(headers[HTTP_HEADER_TRACE_ID]), span.trace_id)
            eq_(int(headers[HTTP_HEADER_PARENT_ID]), span.span_id)
Exemple #6
0
    def test_inject(self):
        tracer = DummyTracer()

        ctx = Context(trace_id=1234, sampling_priority=2, dd_origin="synthetics")
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            assert int(headers[HTTP_HEADER_TRACE_ID]) == span.trace_id
            assert int(headers[HTTP_HEADER_PARENT_ID]) == span.span_id
            assert int(headers[HTTP_HEADER_SAMPLING_PRIORITY]) == span.context.sampling_priority
            assert headers[HTTP_HEADER_ORIGIN] == span.context.dd_origin
Exemple #7
0
    def test_inject(self):
        tracer = get_dummy_tracer()

        with tracer.trace("global_root_span") as span:
            span.context.sampling_priority = 2
            span.context._dd_origin = "synthetics"
            headers = {}
            propagator = HTTPPropagator()
            propagator.inject(span.context, headers)

            assert int(headers[HTTP_HEADER_TRACE_ID]) == span.trace_id
            assert int(headers[HTTP_HEADER_PARENT_ID]) == span.span_id
            assert int(headers[HTTP_HEADER_SAMPLING_PRIORITY]) == span.context.sampling_priority
            assert headers[HTTP_HEADER_ORIGIN] == span.context._dd_origin
Exemple #8
0
    def test_inject(self):
        tracer = get_dummy_tracer()

        with tracer.trace("global_root_span") as span:
            span.context.sampling_priority = 2
            headers = {}
            propagator = HTTPPropagator()
            propagator.inject(span.context, headers)

            eq_(int(headers[HTTP_HEADER_TRACE_ID]), span.trace_id)
            eq_(int(headers[HTTP_HEADER_PARENT_ID]), span.span_id)
            eq_(
                int(headers[HTTP_HEADER_SAMPLING_PRIORITY]),
                span.context.sampling_priority,
            )
Exemple #9
0
    def test_b3_inject(self):
        tracer = get_dummy_tracer()
        tracer.configure(http_propagator=B3HTTPPropagator)

        with tracer.trace("global_root_span") as span:
            headers = {}
            set_http_propagator_factory(B3HTTPPropagator)
            propagator = HTTPPropagator()
            propagator.inject(span.context, headers)

            assert int(headers[B3HTTPPropagator.TRACE_ID_KEY],
                       16) == span.trace_id
            assert int(headers[B3HTTPPropagator.SPAN_ID_KEY],
                       16) == span.span_id
            assert int(headers[B3HTTPPropagator.SAMPLED_KEY]) == 1
Exemple #10
0
    def test_inject_tags_unicode(self):
        """Unicode characters are not allowed"""
        tracer = DummyTracer()

        meta = {u"_dd.p.unicode_☺️": u"unicode value ☺️"}
        ctx = Context(trace_id=1234,
                      sampling_priority=2,
                      dd_origin="synthetics",
                      meta=meta)
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            assert HTTP_HEADER_TAGS not in headers
            assert ctx._meta["_dd.propagation_error"] == "encoding_error"
Exemple #11
0
    def test_inject_tags_invalid(self):
        tracer = DummyTracer()

        # DEV: "=" and "," are not allowed in keys or values
        meta = {"_dd.p.test=": ",value="}
        ctx = Context(trace_id=1234,
                      sampling_priority=2,
                      dd_origin="synthetics",
                      meta=meta)
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            assert HTTP_HEADER_TAGS not in headers
            assert ctx._meta["_dd.propagation_error"] == "encoding_error"
Exemple #12
0
    def test_inject_tags_many_large(self):
        """When we have too many tags that cause us to reach the max size limit"""
        tracer = DummyTracer()

        meta = {"_dd.p.test_{}".format(i): "test" * 10 for i in range(100)}
        ctx = Context(trace_id=1234,
                      sampling_priority=2,
                      dd_origin="synthetics",
                      meta=meta)
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            assert HTTP_HEADER_TAGS not in headers
            assert ctx._meta["_dd.propagation_error"] == "max_size"
Exemple #13
0
    def test_inject_tags_large(self):
        """When we have a single large tag that won't fit"""
        tracer = DummyTracer()

        # DEV: Limit is 512
        meta = {"_dd.p.test": "long" * 200}
        ctx = Context(trace_id=1234,
                      sampling_priority=2,
                      dd_origin="synthetics",
                      meta=meta)
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            assert HTTP_HEADER_TAGS not in headers
            assert ctx._meta["_dd.propagation_error"] == "max_size"
    def test_distributed_tracing_propagation(self):
        @self.app.task
        def fn_task():
            return 42

        # This header manipulation is copying the work that should be done
        # by the before_publish signal. Rip it out if Celery ever fixes their bug.
        current_context = Pin.get_from(self.app).tracer.context_provider.active()
        headers = {}
        HTTPPropagator.inject(current_context, headers)

        with self.override_config("celery", dict(distributed_tracing=True)):
            fn_task.apply(headers=headers)

        traces = self.pop_traces()
        span = traces[0][0]
        assert span.trace_id == 12345
Exemple #15
0
    def test_inject_tags_bytes(self):
        """We properly encode when the meta key as long as it is just ascii characters"""
        tracer = DummyTracer()

        # Context._meta allows str and bytes for keys
        meta = {u"_dd.p.unicode": u"unicode", b"_dd.p.bytes": b"bytes"}
        ctx = Context(trace_id=1234,
                      sampling_priority=2,
                      dd_origin="synthetics",
                      meta=meta)
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            # The ordering is non-deterministic, so compare as a list of tags
            tags = set(headers[HTTP_HEADER_TAGS].split(","))
            assert tags == set(["_dd.p.unicode=unicode", "_dd.p.bytes=bytes"])
Exemple #16
0
    def test_inject_tags_previous_error(self):
        """When we have previously gotten an error, do not try to propagate tags"""
        tracer = DummyTracer()

        # This value is valid
        meta = {
            "_dd.p.key": "value",
            "_dd.propagation_error": "some fake test value"
        }
        ctx = Context(trace_id=1234,
                      sampling_priority=2,
                      dd_origin="synthetics",
                      meta=meta)
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            assert HTTP_HEADER_TAGS not in headers
Exemple #17
0
def _init_span(span, request):
    # type: (Span, httpx.Request) -> None
    if config.httpx.split_by_domain:
        if hasattr(request.url, "netloc"):
            span.service = request.url.netloc
        else:
            service = ensure_binary(request.url.host)
            if request.url.port:
                service += b":" + ensure_binary(str(request.url.port))
            span.service = service

    span.set_tag(SPAN_MEASURED_KEY)

    if distributed_tracing_enabled(config.httpx):
        HTTPPropagator.inject(span.context, request.headers)

    sample_rate = config.httpx.get_analytics_sample_rate(use_global_config=True)
    if sample_rate is not None:
        span.set_tag(ANALYTICS_SAMPLE_RATE_KEY, sample_rate)
Exemple #18
0
    def test_inject(self):
        tracer = DummyTracer()

        # We will only pass along `_dd.p.*` tags
        meta = {"_dd.p.test": "value", "non._dd.p_tag": "value"}
        ctx = Context(trace_id=1234,
                      sampling_priority=2,
                      dd_origin="synthetics",
                      meta=meta)
        tracer.context_provider.activate(ctx)
        with tracer.trace("global_root_span") as span:
            headers = {}
            HTTPPropagator.inject(span.context, headers)

            assert int(headers[HTTP_HEADER_TRACE_ID]) == span.trace_id
            assert int(headers[HTTP_HEADER_PARENT_ID]) == span.span_id
            assert int(headers[HTTP_HEADER_SAMPLING_PRIORITY]
                       ) == span.context.sampling_priority
            assert headers[HTTP_HEADER_ORIGIN] == span.context.dd_origin
Exemple #19
0
    def inject(span_context, carrier):
        """Inject a span context into a carrier.

        *span_context* is injected into the carrier by first using an
        :class:`ddtrace.propagation.http.HTTPPropagator` to inject the ddtracer
        specific fields.

        Then the baggage is injected into *carrier*.

        :param span_context: span context to inject.

        :param carrier: carrier to inject into.
        """
        if not isinstance(carrier, dict):
            raise InvalidCarrierException("propagator expects carrier to be a dict")

        DDHTTPPropagator.inject(span_context._dd_context, carrier)

        # Add the baggage
        if span_context.baggage is not None:
            for key in span_context.baggage:
                carrier[HTTP_BAGGAGE_PREFIX + key] = span_context.baggage[key]
class HTTPPropagator(Propagator):
    """OpenTracing compatible HTTP_HEADER and TEXT_MAP format propagator.

    `HTTPPropagator` provides compatibility by using existing OpenTracing
    compatible methods from the ddtracer along with new logic supporting the
    outstanding OpenTracing-defined functionality.
    """

    __slots__ = ['_dd_propagator']

    def __init__(self):
        self._dd_propagator = DDHTTPPropagator()

    def inject(self, span_context, carrier):
        """Inject a span context into a carrier.

        *span_context* is injected into the carrier by first using an
        :class:`ddtrace.propagation.http.HTTPPropagator` to inject the ddtracer
        specific fields.

        Then the baggage is injected into *carrier*.

        :param span_context: span context to inject.

        :param carrier: carrier to inject into.
        """
        if not isinstance(carrier, dict):
            raise InvalidCarrierException(
                'propagator expects carrier to be a dict')

        self._dd_propagator.inject(span_context._dd_context, carrier)

        # Add the baggage
        if span_context.baggage is not None:
            for key in span_context.baggage:
                carrier[HTTP_BAGGAGE_PREFIX + key] = span_context.baggage[key]

    def extract(self, carrier):
        """Extract a span context from a carrier.

        :class:`ddtrace.propagation.http.HTTPPropagator` is used to extract
        ddtracer supported fields into a `ddtrace.Context` context which is
        combined with new logic to extract the baggage which is returned in an
        OpenTracing compatible span context.

        :param carrier: carrier to extract from.

        :return: extracted span context.
        """
        if not isinstance(carrier, dict):
            raise InvalidCarrierException(
                'propagator expects carrier to be a dict')

        ddspan_ctx = self._dd_propagator.extract(carrier)

        # if the dd propagator fails then it will return a new empty span
        # context (with trace_id=None), we however want to raise an exception
        # if this occurs.
        if not ddspan_ctx.trace_id:
            raise SpanContextCorruptedException(
                'failed to extract span context')

        baggage = {}
        for key in carrier:
            if key.startswith(HTTP_BAGGAGE_PREFIX):
                baggage[key[HTTP_BAGGAGE_PREFIX_LEN:]] = carrier[key]

        return SpanContext(ddcontext=ddspan_ctx, baggage=baggage)