def test_origin(self):
        context = trace_api.SpanContext(
            trace_id=0x000000000000000000000000DEADBEEF,
            span_id=trace_api.INVALID_SPAN,
            is_remote=True,
            trace_state=trace_api.TraceState(
                {datadog.constants.DD_ORIGIN: "origin-service"}),
        )

        root_span = trace.Span(name="root", context=context, parent=None)
        child_span = trace.Span(name="child",
                                context=context,
                                parent=root_span)
        root_span.start()
        child_span.start()
        child_span.end()
        root_span.end()

        # pylint: disable=protected-access
        exporter = datadog.DatadogSpanExporter()
        datadog_spans = [
            span.to_dict()
            for span in exporter._translate_to_datadog([root_span, child_span])
        ]

        self.assertEqual(len(datadog_spans), 2)

        actual = [
            span["meta"].get(datadog.constants.DD_ORIGIN)
            if "meta" in span else None for span in datadog_spans
        ]
        expected = ["origin-service", None]
        self.assertListEqual(actual, expected)
    def test_probability_sampler(self):
        trace_state = trace.TraceState({"key": "value"})
        sampler = sampling.TraceIdRatioBased(0.5)

        # Check that we sample based on the trace ID if the parent context is
        # null
        sampled_result = sampler.should_sample(
            None,
            0x7FFFFFFFFFFFFFFF,
            "sampled true",
            attributes={"sampled.expect": "true"},
            trace_state=trace_state,
        )
        self.assertTrue(sampled_result.decision.is_sampled())
        self.assertEqual(sampled_result.attributes, {"sampled.expect": "true"})
        self.assertEqual(sampled_result.trace_state, trace_state)

        not_sampled_result = sampler.should_sample(
            None,
            0x8000000000000000,
            "sampled false",
            attributes={"sampled.expect": "false"},
            trace_state=trace_state,
        )
        self.assertFalse(not_sampled_result.decision.is_sampled())
        self.assertEqual(not_sampled_result.attributes, {})
        self.assertEqual(not_sampled_result.trace_state, trace_state)
Пример #3
0
    def extract(
        self,
        get_from_carrier: Getter[HTTPTextFormatT],
        carrier: HTTPTextFormatT,
        context: typing.Optional[Context] = None,
    ) -> Context:
        trace_id = format_trace_id(trace.INVALID_TRACE_ID)
        span_id = format_span_id(trace.INVALID_SPAN_ID)
        sampled = "0"
        flags = None

        single_header = _extract_first_element(
            get_from_carrier(carrier, self.SINGLE_HEADER_KEY))
        if single_header:
            # The b3 spec calls for the sampling state to be
            # "deferred", which is unspecified. This concept does not
            # translate to SpanContext, so we set it as recorded.
            sampled = "1"
            fields = single_header.split("-", 4)

            if len(fields) == 1:
                sampled = fields[0]
            elif len(fields) == 2:
                trace_id, span_id = fields
            elif len(fields) == 3:
                trace_id, span_id, sampled = fields
            elif len(fields) == 4:
                trace_id, span_id, sampled, _ = fields
            else:
                return set_span_in_context(trace.INVALID_SPAN)
        else:
            trace_id = (_extract_first_element(
                get_from_carrier(carrier, self.TRACE_ID_KEY)) or trace_id)
            span_id = (_extract_first_element(
                get_from_carrier(carrier, self.SPAN_ID_KEY)) or span_id)
            sampled = (_extract_first_element(
                get_from_carrier(carrier, self.SAMPLED_KEY)) or sampled)
            flags = (_extract_first_element(
                get_from_carrier(carrier, self.FLAGS_KEY)) or flags)

        options = 0
        # The b3 spec provides no defined behavior for both sample and
        # flag values set. Since the setting of at least one implies
        # the desire for some form of sampling, propagate if either
        # header is set to allow.
        if sampled in self._SAMPLE_PROPAGATE_VALUES or flags == "1":
            options |= trace.TraceFlags.SAMPLED
        return set_span_in_context(
            trace.DefaultSpan(
                trace.SpanContext(
                    # trace an span ids are encoded in hex, so must be converted
                    trace_id=int(trace_id, 16),
                    span_id=int(span_id, 16),
                    is_remote=True,
                    trace_flags=trace.TraceFlags(options),
                    trace_state=trace.TraceState(),
                )))
Пример #4
0
    def exec_parent_based(self, parent_sampling_context):
        trace_state = trace.TraceState({"key": "value"})
        sampler = sampling.ParentBased(sampling.ALWAYS_ON)
        with parent_sampling_context(
                self._create_parent_span(trace_flags=TO_DEFAULT)) as context:
            # Check that the sampling decision matches the parent context if given
            not_sampled_result = sampler.should_sample(
                context,
                0x7FFFFFFFFFFFFFFF,
                "unsampled parent, sampling on",
                attributes={"sampled": "false"},
                trace_state=trace_state,
            )
            self.assertFalse(not_sampled_result.decision.is_sampled())
            self.assertEqual(not_sampled_result.attributes, {})
            self.assertEqual(not_sampled_result.trace_state, trace_state)

        with parent_sampling_context(
                self._create_parent_span(trace_flags=TO_SAMPLED)) as context:
            sampler2 = sampling.ParentBased(sampling.ALWAYS_OFF)
            sampled_result = sampler2.should_sample(
                context,
                0x8000000000000000,
                "sampled parent, sampling off",
                attributes={"sampled": "true"},
                trace_state=trace_state,
            )
            self.assertTrue(sampled_result.decision.is_sampled())
            self.assertEqual(sampled_result.attributes, {"sampled": "true"})
            self.assertEqual(sampled_result.trace_state, trace_state)

        # for root span follow decision of delegate sampler
        with parent_sampling_context(trace.INVALID_SPAN) as context:
            sampler3 = sampling.ParentBased(sampling.ALWAYS_OFF)
            not_sampled_result = sampler3.should_sample(
                context,
                0x8000000000000000,
                "parent, sampling off",
                attributes={"sampled": "false"},
                trace_state=trace_state,
            )
            self.assertFalse(not_sampled_result.decision.is_sampled())
            self.assertEqual(not_sampled_result.attributes, {})
            self.assertEqual(not_sampled_result.trace_state, trace_state)

        with parent_sampling_context(trace.INVALID_SPAN) as context:
            sampler4 = sampling.ParentBased(sampling.ALWAYS_ON)
            sampled_result = sampler4.should_sample(
                context,
                0x8000000000000000,
                "no parent, sampling on",
                attributes={"sampled": "true"},
                trace_state=trace_state,
            )
            self.assertTrue(sampled_result.decision.is_sampled())
            self.assertEqual(sampled_result.attributes, {"sampled": "true"})
            self.assertEqual(sampled_result.trace_state, trace_state)
    def extract(
        self,
        getter: Getter[TextMapPropagatorT],
        carrier: TextMapPropagatorT,
        context: typing.Optional[Context] = None,
    ) -> Context:
        trace_header_list = getter.get(carrier, TRACE_HEADER_KEY)

        if not trace_header_list or len(trace_header_list) != 1:
            return trace.set_span_in_context(
                trace.INVALID_SPAN, context=context
            )

        trace_header = trace_header_list[0]

        if not trace_header:
            return trace.set_span_in_context(
                trace.INVALID_SPAN, context=context
            )

        try:
            (
                trace_id,
                span_id,
                sampled,
            ) = AwsXRayFormat._extract_span_properties(trace_header)
        except AwsParseTraceHeaderError as err:
            _logger.debug(err.message)
            return trace.set_span_in_context(
                trace.INVALID_SPAN, context=context
            )

        options = 0
        if sampled:
            options |= trace.TraceFlags.SAMPLED

        span_context = trace.SpanContext(
            trace_id=trace_id,
            span_id=span_id,
            is_remote=True,
            trace_flags=trace.TraceFlags(options),
            trace_state=trace.TraceState(),
        )

        if not span_context.is_valid:
            _logger.debug(
                "Invalid Span Extracted. Insertting INVALID span into provided context."
            )
            return trace.set_span_in_context(
                trace.INVALID_SPAN, context=context
            )

        return trace.set_span_in_context(
            trace.DefaultSpan(span_context), context=context
        )
Пример #6
0
def _parse_tracestate(header_list: typing.List[str]) -> trace.TraceState:
    """Parse one or more w3c tracestate header into a TraceState.

    Args:
        string: the value of the tracestate header.

    Returns:
        A valid TraceState that contains values extracted from
        the tracestate header.

        If the format of one headers is illegal, all values will
        be discarded and an empty tracestate will be returned.

        If the number of keys is beyond the maximum, all values
        will be discarded and an empty tracestate will be returned.
    """
    tracestate = trace.TraceState()
    value_count = 0
    for header in header_list:
        for member in re.split(_DELIMITER_FORMAT_RE, header):
            # empty members are valid, but no need to process further.
            if not member:
                continue
            match = _MEMBER_FORMAT_RE.fullmatch(member)
            if not match:
                # TODO: log this?
                return trace.TraceState()
            key, _eq, value = match.groups()
            if key in tracestate:  # pylint:disable=E1135
                # duplicate keys are not legal in
                # the header, so we will remove
                return trace.TraceState()
            # typing.Dict's update is not recognized by pylint:
            # https://github.com/PyCQA/pylint/issues/2420
            tracestate[key] = value  # pylint:disable=E1137
            value_count += 1
            if value_count > _TRACECONTEXT_MAXIMUM_TRACESTATE_KEYS:
                return trace.TraceState()
    return tracestate
 def test_always_off(self):
     trace_state = trace.TraceState({"key": "value"})
     test_data = (TO_DEFAULT, TO_SAMPLED, None)
     for trace_flags in test_data:
         with self.subTest(trace_flags=trace_flags):
             context = self._create_parent(trace_flags)
             sample_result = sampling.ALWAYS_OFF.should_sample(
                 context,
                 0xDEADBEF1,
                 "sampling off",
                 attributes={"sampled.expect": "false"},
                 trace_state=trace_state,
             )
             self.assertFalse(sample_result.decision.is_sampled())
             self.assertEqual(sample_result.attributes, {})
             self.assertEqual(sample_result.trace_state, trace_state)
Пример #8
0
 def test_always_off(self):
     trace_state = trace.TraceState([("key", "value")])
     test_data = (TO_DEFAULT, TO_SAMPLED, None)
     for trace_flags in test_data:
         with self.subTest(trace_flags=trace_flags):
             context = self._create_parent(trace_flags, False, trace_state)
             sample_result = sampling.ALWAYS_OFF.should_sample(
                 context,
                 0xDEADBEF1,
                 "sampling off",
                 trace.SpanKind.INTERNAL,
                 attributes={"sampled.expect": "false"},
             )
             self.assertFalse(sample_result.decision.is_sampled())
             self.assertEqual(sample_result.attributes, {})
             if context is not None:
                 self.assertEqual(sample_result.trace_state, trace_state)
             else:
                 self.assertIsNone(sample_result.trace_state)
    def extract(
        self,
        carrier: CarrierT,
        context: typing.Optional[Context] = None,
        getter: Getter = default_getter,
    ) -> Context:
        if context is None:
            context = Context()

        trace_id = extract_first_element(getter.get(carrier,
                                                    self.TRACE_ID_KEY))

        span_id = extract_first_element(getter.get(carrier,
                                                   self.PARENT_ID_KEY))

        sampled = extract_first_element(
            getter.get(carrier, self.SAMPLING_PRIORITY_KEY))

        origin = extract_first_element(getter.get(carrier, self.ORIGIN_KEY))

        trace_flags = trace.TraceFlags()
        if sampled and int(sampled) in (
                constants.AUTO_KEEP,
                constants.USER_KEEP,
        ):
            trace_flags = trace.TraceFlags(trace.TraceFlags.SAMPLED)

        if trace_id is None or span_id is None:
            return context

        trace_state = []
        if origin is not None:
            trace_state.append((constants.DD_ORIGIN, origin))
        span_context = trace.SpanContext(
            trace_id=int(trace_id),
            span_id=int(span_id),
            is_remote=True,
            trace_flags=trace_flags,
            trace_state=trace.TraceState(trace_state),
        )

        return set_span_in_context(trace.NonRecordingSpan(span_context),
                                   context)
Пример #10
0
 def mock_opentelemetry_context(trace_id=0xDEADBEEF,
                                span_id=0xBEEF,
                                trace_flags=None,
                                trace_state=None):
     span_context = trace.SpanContext(
         trace_id=trace_id,
         span_id=span_id,
         is_remote=True,
         trace_flags=trace_flags,
         trace_state=trace.TraceState(
             **(trace_state if trace_state is not None else {
                 "some_key": "some_value"
             })),
     )
     ctx = trace.set_span_in_context(trace.DefaultSpan(span_context))
     token = context.attach(ctx)
     try:
         yield
     finally:
         context.detach(token)
Пример #11
0
    def extract(
        self,
        get_from_carrier: Getter[TextMapPropagatorT],
        carrier: TextMapPropagatorT,
        context: typing.Optional[Context] = None,
    ) -> Context:
        trace_id = extract_first_element(
            get_from_carrier(carrier, self.TRACE_ID_KEY)
        )

        span_id = extract_first_element(
            get_from_carrier(carrier, self.PARENT_ID_KEY)
        )

        sampled = extract_first_element(
            get_from_carrier(carrier, self.SAMPLING_PRIORITY_KEY)
        )

        origin = extract_first_element(
            get_from_carrier(carrier, self.ORIGIN_KEY)
        )

        trace_flags = trace.TraceFlags()
        if sampled and int(sampled) in (
            constants.AUTO_KEEP,
            constants.USER_KEEP,
        ):
            trace_flags |= trace.TraceFlags.SAMPLED

        if trace_id is None or span_id is None:
            return set_span_in_context(trace.INVALID_SPAN, context)

        span_context = trace.SpanContext(
            trace_id=int(trace_id),
            span_id=int(span_id),
            is_remote=True,
            trace_flags=trace_flags,
            trace_state=trace.TraceState({constants.DD_ORIGIN: origin}),
        )

        return set_span_in_context(trace.DefaultSpan(span_context), context)
Пример #12
0
    def mock_opentelemetry_context(trace_id=0xDEADBEEF,
                                   span_id=0xBEEF,
                                   trace_flags=None,
                                   trace_state=None):
        if trace_state is None:
            trace_state = [("some_key", "some_value")]

        span_context = trace.SpanContext(
            trace_id=trace_id,
            span_id=span_id,
            is_remote=True,
            trace_flags=trace_flags,
            trace_state=trace.TraceState(trace_state),
        )
        ctx = trace.set_span_in_context(
            trace.span.NonRecordingSpan(span_context))
        token = context.attach(ctx)
        try:
            yield
        finally:
            context.detach(token)
    def test_default_on(self):
        trace_state = trace.TraceState({"key": "value"})
        context = self._create_parent(trace_flags=TO_DEFAULT)
        sample_result = sampling.DEFAULT_ON.should_sample(
            context,
            0xDEADBEF1,
            "unsampled parent, sampling on",
            attributes={"sampled.expect": "false"},
            trace_state=trace_state,
        )
        self.assertFalse(sample_result.decision.is_sampled())
        self.assertEqual(sample_result.attributes, {})
        self.assertEqual(sample_result.trace_state, trace_state)

        context = self._create_parent(trace_flags=TO_SAMPLED)
        sample_result = sampling.DEFAULT_ON.should_sample(
            context,
            0xDEADBEF1,
            "sampled parent, sampling on",
            attributes={"sampled.expect": "true"},
            trace_state=trace_state,
        )
        self.assertTrue(sample_result.decision.is_sampled())
        self.assertEqual(sample_result.attributes, {"sampled.expect": "true"})
        self.assertEqual(sample_result.trace_state, trace_state)

        sample_result = sampling.DEFAULT_ON.should_sample(
            None,
            0xDEADBEF1,
            "no parent, sampling on",
            attributes={"sampled.expect": "true"},
            trace_state=trace_state,
        )
        self.assertTrue(sample_result.decision.is_sampled())
        self.assertEqual(sample_result.attributes, {"sampled.expect": "true"})
        self.assertEqual(sample_result.trace_state, trace_state)
Пример #14
0
    def test_default_off(self):
        trace_state = trace.TraceState([("key", "value")])
        context = self._create_parent(TO_DEFAULT, False, trace_state)
        sample_result = sampling.DEFAULT_OFF.should_sample(
            context,
            0xDEADBEF1,
            "unsampled parent, sampling off",
            trace.SpanKind.INTERNAL,
            attributes={"sampled.expect", "false"},
        )
        self.assertFalse(sample_result.decision.is_sampled())
        self.assertEqual(sample_result.attributes, {})
        self.assertEqual(sample_result.trace_state, trace_state)

        context = self._create_parent(TO_SAMPLED, False, trace_state)
        sample_result = sampling.DEFAULT_OFF.should_sample(
            context,
            0xDEADBEF1,
            "sampled parent, sampling on",
            trace.SpanKind.INTERNAL,
            attributes={"sampled.expect": "true"},
        )
        self.assertTrue(sample_result.decision.is_sampled())
        self.assertEqual(sample_result.attributes, {"sampled.expect": "true"})
        self.assertEqual(sample_result.trace_state, trace_state)

        default_off = sampling.DEFAULT_OFF.should_sample(
            None,
            0xDEADBEF1,
            "unsampled parent, sampling off",
            trace.SpanKind.INTERNAL,
            attributes={"sampled.expect": "false"},
        )
        self.assertFalse(default_off.decision.is_sampled())
        self.assertEqual(default_off.attributes, {})
        self.assertIsNone(default_off.trace_state)
Пример #15
0
    def exec_parent_based(self, parent_sampling_context):
        trace_state = trace.TraceState([("key", "value")])
        sampler = sampling.ParentBased(sampling.ALWAYS_ON)
        # Check that the sampling decision matches the parent context if given
        with parent_sampling_context(
                self._create_parent_span(
                    trace_flags=TO_DEFAULT,
                    trace_state=trace_state,
                )) as context:
            # local, not sampled
            not_sampled_result = sampler.should_sample(
                context,
                0x7FFFFFFFFFFFFFFF,
                "unsampled parent, sampling on",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "false"},
            )
            self.assertFalse(not_sampled_result.decision.is_sampled())
            self.assertEqual(not_sampled_result.attributes, {})
            self.assertEqual(not_sampled_result.trace_state, trace_state)

        with parent_sampling_context(
                self._create_parent_span(
                    trace_flags=TO_DEFAULT,
                    trace_state=trace_state,
                )) as context:
            sampler = sampling.ParentBased(
                root=sampling.ALWAYS_OFF,
                local_parent_not_sampled=sampling.ALWAYS_ON,
            )
            # local, not sampled -> opposite sampler
            sampled_result = sampler.should_sample(
                context,
                0x7FFFFFFFFFFFFFFF,
                "unsampled parent, sampling on",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "false"},
            )
            self.assertTrue(sampled_result.decision.is_sampled())
            self.assertEqual(sampled_result.attributes, {"sampled": "false"})
            self.assertEqual(sampled_result.trace_state, trace_state)

        with parent_sampling_context(
                self._create_parent_span(
                    trace_flags=TO_SAMPLED,
                    trace_state=trace_state,
                )) as context:
            sampler = sampling.ParentBased(sampling.ALWAYS_OFF)
            # local, sampled
            sampled_result = sampler.should_sample(
                context,
                0x8000000000000000,
                "sampled parent, sampling off",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "true"},
                trace_state=trace_state,
            )
            self.assertTrue(sampled_result.decision.is_sampled())
            self.assertEqual(sampled_result.attributes, {"sampled": "true"})
            self.assertEqual(sampled_result.trace_state, trace_state)

        with parent_sampling_context(
                self._create_parent_span(
                    trace_flags=TO_SAMPLED,
                    trace_state=trace_state,
                )) as context:
            sampler = sampling.ParentBased(
                root=sampling.ALWAYS_ON,
                local_parent_sampled=sampling.ALWAYS_OFF,
            )
            # local, sampled -> opposite sampler
            not_sampled_result = sampler.should_sample(
                context,
                0x7FFFFFFFFFFFFFFF,
                "unsampled parent, sampling on",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "false"},
                trace_state=trace_state,
            )
            self.assertFalse(not_sampled_result.decision.is_sampled())
            self.assertEqual(not_sampled_result.attributes, {})
            self.assertEqual(not_sampled_result.trace_state, trace_state)

        with parent_sampling_context(
                self._create_parent_span(
                    trace_flags=TO_DEFAULT,
                    is_remote=True,
                    trace_state=trace_state,
                )) as context:
            sampler = sampling.ParentBased(sampling.ALWAYS_ON)
            # remote, not sampled
            not_sampled_result = sampler.should_sample(
                context,
                0x7FFFFFFFFFFFFFFF,
                "unsampled parent, sampling on",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "false"},
                trace_state=trace_state,
            )
            self.assertFalse(not_sampled_result.decision.is_sampled())
            self.assertEqual(not_sampled_result.attributes, {})
            self.assertEqual(not_sampled_result.trace_state, trace_state)

        with parent_sampling_context(
                self._create_parent_span(
                    trace_flags=TO_DEFAULT,
                    is_remote=True,
                    trace_state=trace_state,
                )) as context:
            sampler = sampling.ParentBased(
                root=sampling.ALWAYS_OFF,
                remote_parent_not_sampled=sampling.ALWAYS_ON,
            )
            # remote, not sampled -> opposite sampler
            sampled_result = sampler.should_sample(
                context,
                0x7FFFFFFFFFFFFFFF,
                "unsampled parent, sampling on",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "false"},
            )
            self.assertTrue(sampled_result.decision.is_sampled())
            self.assertEqual(sampled_result.attributes, {"sampled": "false"})
            self.assertEqual(sampled_result.trace_state, trace_state)

        with parent_sampling_context(
                self._create_parent_span(
                    trace_flags=TO_SAMPLED,
                    is_remote=True,
                    trace_state=trace_state,
                )) as context:
            sampler = sampling.ParentBased(sampling.ALWAYS_OFF)
            # remote, sampled
            sampled_result = sampler.should_sample(
                context,
                0x8000000000000000,
                "sampled parent, sampling off",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "true"},
            )
            self.assertTrue(sampled_result.decision.is_sampled())
            self.assertEqual(sampled_result.attributes, {"sampled": "true"})
            self.assertEqual(sampled_result.trace_state, trace_state)

        with parent_sampling_context(
                self._create_parent_span(
                    trace_flags=TO_SAMPLED,
                    is_remote=True,
                    trace_state=trace_state,
                )) as context:
            sampler = sampling.ParentBased(
                root=sampling.ALWAYS_ON,
                remote_parent_sampled=sampling.ALWAYS_OFF,
            )
            # remote, sampled -> opposite sampler
            not_sampled_result = sampler.should_sample(
                context,
                0x7FFFFFFFFFFFFFFF,
                "unsampled parent, sampling on",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "false"},
            )
            self.assertFalse(not_sampled_result.decision.is_sampled())
            self.assertEqual(not_sampled_result.attributes, {})
            self.assertEqual(not_sampled_result.trace_state, trace_state)

        # for root span follow decision of root sampler
        with parent_sampling_context(trace.INVALID_SPAN) as context:
            sampler = sampling.ParentBased(sampling.ALWAYS_OFF)
            not_sampled_result = sampler.should_sample(
                context,
                0x8000000000000000,
                "parent, sampling off",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "false"},
            )
            self.assertFalse(not_sampled_result.decision.is_sampled())
            self.assertEqual(not_sampled_result.attributes, {})
            self.assertIsNone(not_sampled_result.trace_state)

        with parent_sampling_context(trace.INVALID_SPAN) as context:
            sampler = sampling.ParentBased(sampling.ALWAYS_ON)
            sampled_result = sampler.should_sample(
                context,
                0x8000000000000000,
                "no parent, sampling on",
                trace.SpanKind.INTERNAL,
                attributes={"sampled": "true"},
                trace_state=trace_state,
            )
            self.assertTrue(sampled_result.decision.is_sampled())
            self.assertEqual(sampled_result.attributes, {"sampled": "true"})
            self.assertIsNone(sampled_result.trace_state)
Пример #16
0
    def extract(
        self,
        get_from_carrier: Getter[TextMapPropagatorT],
        carrier: TextMapPropagatorT,
        context: typing.Optional[Context] = None,
    ) -> Context:
        if not carrier:
            raise ValueError(("Could not extract from carrier: %s", carrier))

        trace_header = get_from_carrier(carrier, self.TRACE_HEADER_KEY)

        if not trace_header or trace_header == "":
            return trace.set_span_in_context(trace.INVALID_SPAN)

        trace_id = trace.INVALID_TRACE_ID
        span_id = trace.INVALID_SPAN_ID
        sampled = False

        next_kv_pair_start = 0

        while next_kv_pair_start < len(trace_header):
            try:
                kv_pair_delimiter_index = trace_header.index(
                    self.KV_PAIR_DELIMITER, next_kv_pair_start
                )
                kv_pair_subset = trace_header[
                    next_kv_pair_start:kv_pair_delimiter_index
                ]
                next_kv_pair_start = kv_pair_delimiter_index + 1
            except ValueError as _:
                kv_pair_subset = trace_header[next_kv_pair_start:]
                next_kv_pair_start = len(trace_header)

            stripped_kv_pair = kv_pair_subset.strip()

            try:
                key_and_value_delimiter_index = stripped_kv_pair.index(
                    self.KEY_AND_VALUE_DELIMITER
                )
            except ValueError as _:
                _logger.error(
                    (
                        "Error parsing X-Ray trace header. Invalid key value pair: %s. Returning INVALID span context.",
                        kv_pair_subset,
                    )
                )
                return trace.set_span_in_context(trace.INVALID_SPAN)

            value = stripped_kv_pair[key_and_value_delimiter_index + 1 :]

            if stripped_kv_pair.startswith(self.TRACE_ID_KEY):
                if (
                    len(value) != self.TRACE_ID_LENGTH
                    or not value.startswith(self.TRACE_ID_VERSION)
                    or value[self.TRACE_ID_DELIMITER_INDEX_1]
                    != self.TRACE_ID_DELIMITER
                    or value[self.TRACE_ID_DELIMITER_INDEX_2]
                    != self.TRACE_ID_DELIMITER
                ):
                    _logger.error(
                        (
                            "Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.",
                            self.TRACE_HEADER_KEY,
                            trace_header,
                        )
                    )
                    return trace.INVALID_SPAN_CONTEXT

                timestamp_subset = value[
                    self.TRACE_ID_DELIMITER_INDEX_1
                    + 1 : self.TRACE_ID_DELIMITER_INDEX_2
                ]
                unique_id_subset = value[
                    self.TRACE_ID_DELIMITER_INDEX_2 + 1 : self.TRACE_ID_LENGTH
                ]
                trace_id = int(timestamp_subset + unique_id_subset, 16)
            elif stripped_kv_pair.startswith(self.PARENT_ID_KEY):
                if len(value) != self.PARENT_ID_LENGTH:
                    _logger.error(
                        (
                            "Invalid ParentId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.",
                            self.TRACE_HEADER_KEY,
                            trace_header,
                        )
                    )
                    return trace.INVALID_SPAN_CONTEXT

                span_id = int(value, 16)
            elif stripped_kv_pair.startswith(self.SAMPLED_FLAG_KEY):
                is_sampled_flag_valid = True

                if len(value) != self.SAMPLED_FLAG_LENGTH:
                    is_sampled_flag_valid = False

                if is_sampled_flag_valid:
                    sampled_flag = value[0]
                    if sampled_flag == self.IS_SAMPLED:
                        sampled = True
                    elif sampled_flag == self.NOT_SAMPLED:
                        sampled = False
                    else:
                        is_sampled_flag_valid = False

                if not is_sampled_flag_valid:
                    _logger.error(
                        (
                            "Invalid Sampling flag in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.",
                            self.TRACE_HEADER_KEY,
                            trace_header,
                        )
                    )
                    return trace.INVALID_SPAN_CONTEXT

        options = 0
        if sampled:
            options |= trace.TraceFlags.SAMPLED

        span_context = trace.SpanContext(
            trace_id=trace_id,
            span_id=span_id,
            is_remote=True,
            trace_flags=trace.TraceFlags(options),
            trace_state=trace.TraceState(),
        )

        if not span_context.is_valid:
            return context

        return trace.set_span_in_context(
            trace.DefaultSpan(span_context), context=context
        )
    def test_translate_to_collector(self):
        trace_id = 0x6E0C63257DE34C926F9EFCD03927272E
        span_id = 0x34BF92DEEFC58C92
        parent_id = 0x1111111111111111
        base_time = 683647322 * 10**9  # in ns
        start_times = (
            base_time,
            base_time + 150 * 10**6,
            base_time + 300 * 10**6,
        )
        durations = (50 * 10**6, 100 * 10**6, 200 * 10**6)
        end_times = (
            start_times[0] + durations[0],
            start_times[1] + durations[1],
            start_times[2] + durations[2],
        )
        span_context = trace_api.SpanContext(
            trace_id,
            span_id,
            is_remote=False,
            trace_flags=TraceFlags(TraceFlags.SAMPLED),
            trace_state=trace_api.TraceState({"testKey": "testValue"}),
        )
        parent_context = trace_api.SpanContext(trace_id,
                                               parent_id,
                                               is_remote=False)
        other_context = trace_api.SpanContext(trace_id,
                                              span_id,
                                              is_remote=False)
        event_attributes = {
            "annotation_bool": True,
            "annotation_string": "annotation_test",
            "key_float": 0.3,
        }
        event_timestamp = base_time + 50 * 10**6
        event = trace.Event(
            name="event0",
            timestamp=event_timestamp,
            attributes=event_attributes,
        )
        link_attributes = {"key_bool": True}
        link_1 = trace_api.Link(context=other_context,
                                attributes=link_attributes)
        link_2 = trace_api.Link(context=parent_context,
                                attributes=link_attributes)
        span_1 = trace.Span(
            name="test1",
            context=span_context,
            parent=parent_context,
            events=(event, ),
            links=(link_1, ),
            kind=trace_api.SpanKind.CLIENT,
        )
        span_2 = trace.Span(
            name="test2",
            context=parent_context,
            parent=None,
            kind=trace_api.SpanKind.SERVER,
        )
        span_3 = trace.Span(
            name="test3",
            context=other_context,
            links=(link_2, ),
            parent=span_2.get_context(),
        )
        otel_spans = [span_1, span_2, span_3]
        otel_spans[0].start(start_time=start_times[0])
        otel_spans[0].set_attribute("key_bool", False)
        otel_spans[0].set_attribute("key_string", "hello_world")
        otel_spans[0].set_attribute("key_float", 111.22)
        otel_spans[0].set_attribute("key_int", 333)
        otel_spans[0].set_status(
            trace_api.Status(
                trace_api.status.StatusCanonicalCode.INTERNAL,
                "test description",
            ))
        otel_spans[0].end(end_time=end_times[0])
        otel_spans[1].start(start_time=start_times[1])
        otel_spans[1].set_status(
            trace_api.Status(
                trace_api.status.StatusCanonicalCode.INTERNAL,
                {"test", "val"},
            ))
        otel_spans[1].end(end_time=end_times[1])
        otel_spans[2].start(start_time=start_times[2])
        otel_spans[2].end(end_time=end_times[2])
        output_spans = translate_to_collector(otel_spans)

        self.assertEqual(len(output_spans), 3)
        self.assertEqual(output_spans[0].trace_id,
                         b"n\x0cc%}\xe3L\x92o\x9e\xfc\xd09''.")
        self.assertEqual(output_spans[0].span_id,
                         b"4\xbf\x92\xde\xef\xc5\x8c\x92")
        self.assertEqual(output_spans[0].name,
                         trace_pb2.TruncatableString(value="test1"))
        self.assertEqual(output_spans[1].name,
                         trace_pb2.TruncatableString(value="test2"))
        self.assertEqual(output_spans[2].name,
                         trace_pb2.TruncatableString(value="test3"))
        self.assertEqual(
            output_spans[0].start_time.seconds,
            int(start_times[0] / 1000000000),
        )
        self.assertEqual(output_spans[0].end_time.seconds,
                         int(end_times[0] / 1000000000))
        self.assertEqual(output_spans[0].kind, trace_api.SpanKind.CLIENT.value)
        self.assertEqual(output_spans[1].kind, trace_api.SpanKind.SERVER.value)

        self.assertEqual(output_spans[0].parent_span_id,
                         b"\x11\x11\x11\x11\x11\x11\x11\x11")
        self.assertEqual(output_spans[2].parent_span_id,
                         b"\x11\x11\x11\x11\x11\x11\x11\x11")
        self.assertEqual(
            output_spans[0].status.code,
            trace_api.status.StatusCanonicalCode.INTERNAL.value,
        )
        self.assertEqual(output_spans[0].status.message, "test description")
        self.assertEqual(len(output_spans[0].tracestate.entries), 1)
        self.assertEqual(output_spans[0].tracestate.entries[0].key, "testKey")
        self.assertEqual(output_spans[0].tracestate.entries[0].value,
                         "testValue")

        self.assertEqual(
            output_spans[0].attributes.attribute_map["key_bool"].bool_value,
            False,
        )
        self.assertEqual(
            output_spans[0].attributes.attribute_map["key_string"].
            string_value.value,
            "hello_world",
        )
        self.assertEqual(
            output_spans[0].attributes.attribute_map["key_float"].double_value,
            111.22,
        )
        self.assertEqual(
            output_spans[0].attributes.attribute_map["key_int"].int_value, 333)

        self.assertEqual(
            output_spans[0].time_events.time_event[0].time.seconds, 683647322)
        self.assertEqual(
            output_spans[0].time_events.time_event[0].annotation.description.
            value,
            "event0",
        )
        self.assertEqual(
            output_spans[0].time_events.time_event[0].annotation.attributes.
            attribute_map["annotation_bool"].bool_value,
            True,
        )
        self.assertEqual(
            output_spans[0].time_events.time_event[0].annotation.attributes.
            attribute_map["annotation_string"].string_value.value,
            "annotation_test",
        )
        self.assertEqual(
            output_spans[0].time_events.time_event[0].annotation.attributes.
            attribute_map["key_float"].double_value,
            0.3,
        )

        self.assertEqual(
            output_spans[0].links.link[0].trace_id,
            b"n\x0cc%}\xe3L\x92o\x9e\xfc\xd09''.",
        )
        self.assertEqual(
            output_spans[0].links.link[0].span_id,
            b"4\xbf\x92\xde\xef\xc5\x8c\x92",
        )
        self.assertEqual(
            output_spans[0].links.link[0].type,
            trace_pb2.Span.Link.Type.TYPE_UNSPECIFIED,
        )
        self.assertEqual(
            output_spans[1].status.code,
            trace_api.status.StatusCanonicalCode.INTERNAL.value,
        )
        self.assertEqual(
            output_spans[2].links.link[0].type,
            trace_pb2.Span.Link.Type.PARENT_LINKED_SPAN,
        )
        self.assertEqual(
            output_spans[0].links.link[0].attributes.attribute_map["key_bool"].
            bool_value,
            True,
        )