コード例 #1
0
def test_non_sampled_span_thrift(recorder):

    mock_connection = MockConnection()
    mock_connection.open()

    non_sampled_span = BasicSpan(
        lightstep.tracer._LightstepTracer(False, recorder, None),
        operation_name="non_sampled",
        context=SpanContext(trace_id=1, span_id=1, sampled=False),
        start_time=time.time(),
    )
    non_sampled_span.finish()

    sampled_span = BasicSpan(
        lightstep.tracer._LightstepTracer(False, recorder, None),
        operation_name="sampled",
        context=SpanContext(trace_id=1, span_id=2, sampled=True),
        start_time=time.time(),
    )
    sampled_span.finish()
    recorder.record_span(non_sampled_span)
    recorder.record_span(sampled_span)

    recorder.flush(mock_connection)

    if recorder.use_thrift:
        for span_record in mock_connection.reports[0].span_records:
            assert span_record.span_name == "sampled"
    else:
        for span in mock_connection.reports[0].spans:
            assert span.operation_name == "sampled"
コード例 #2
0
    def extract(self, carrier):
        count = 0
        span_id, trace_id, sampled = (0, 0, False)
        baggage = {}
        for k in carrier:
            v = carrier[k]
            k = k.lower()
            if k == field_name_span_id:
                span_id = int(v, 16)
                count += 1
            elif k == field_name_trace_id:
                trace_id = int(v, 16)
                count += 1
            elif k == field_name_sampled:
                if v == "1":
                    sampled = True
                elif v == "0":
                    sampled = False
                else:
                    raise SpanContextCorruptedException()
                count += 1

        if count != field_count:
            raise SpanContextCorruptedException()

        return SpanContext(span_id=span_id,
                           trace_id=trace_id,
                           baggage=baggage,
                           sampled=sampled)
コード例 #3
0
    def extract(self, carrier):  # noqa
        try:
            if type(carrier) is dict or hasattr(carrier, "__dict__"):
                dc = carrier
            elif type(carrier) is list:
                dc = dict(carrier)
            else:
                raise ot.SpanContextCorruptedException()

            # Look for standard X-Instana-T/S format
            if self.HEADER_KEY_T in dc and self.header_key_s in dc:
                trace_id = util.header_to_id(dc[self.HEADER_KEY_T])
                span_id = util.header_to_id(dc[self.HEADER_KEY_S])

            # Alternatively check for alternate HTTP_X_INSTANA_T/S style
            elif self.ALT_HEADER_KEY_T in dc and self.ALT_HEADER_KEY_S in dc:
                trace_id = util.header_to_id(dc[self.ALT_HEADER_KEY_T])
                span_id = util.header_to_id(dc[self.ALT_HEADER_KEY_S])

            return SpanContext(span_id=span_id,
                               trace_id=trace_id,
                               baggage={},
                               sampled=True)

        except Exception as e:
            log.debug("extract error: ", str(e))
コード例 #4
0
 async def read_loop(self, *args, **kwargs):
     try:
         while not self.stopped:
             msg = await self.inner_read_message(*args, **kwargs)
             assert type(msg) == dict, 'Msg is: {!r}'.format(msg)
             ctx_headers = msg['context_headers']
             if self.remote:
                 parent_ctx = SpanContext(**ctx_headers)
                 method = msg['method']
                 ctx = Context(self.discovery, self.endpoint.service,
                               parent_ctx, method)
                 self.log.debug('CTX: {}'.format(ctx.span.context.trace_id))
                 call_args = msg.get('args', ())
                 call_kwargs = msg.get('kwargs', {})
                 hc = self.handle_call(method, ctx, *call_args,
                                       **call_kwargs)
                 if isinstance(hc, CoroutineType):
                     resp = await hc
                 else:
                     resp = hc
                 self.log.debug('Remote send resp ==> {}'.format(resp))
                 response = {
                     'context_headers': msg['context_headers'],
                     'method': msg['method'],
                     'response': resp
                 }
                 await self.remote_send_response(msg, response)
             else:
                 self.log.debug('Proxy return resp: {}'.format(msg))
                 self.proxy_send_response(msg)
     except asyncio.CancelledError:
         pass
     except Exception as e:
         self.log.exception('In read loop')
         self.terminate(e)
コード例 #5
0
    def extract(self, carrier):  # noqa
        count = 0
        span_id, trace_id, sampled = (0, 0, False)
        baggage = {}
        for k in carrier:
            v = carrier[k]
            k = k.lower()
            if k == field_name_span_id:
                span_id = v
                count += 1
            elif k == field_name_trace_id:
                trace_id = v
                count += 1
            elif k == field_name_sampled:
                if v == str(True).lower():
                    sampled = True
                elif v == str(False).lower():
                    sampled = False
                else:
                    raise SpanContextCorruptedException()
                count += 1
            elif k.startswith(prefix_baggage):
                baggage[k[len(prefix_baggage):]] = v

        if count != field_count:
            raise SpanContextCorruptedException()

        return SpanContext(span_id=span_id,
                           trace_id=trace_id,
                           baggage=baggage,
                           sampled=sampled)
コード例 #6
0
 def dummy_basic_span(self, recorder, i):
     return BasicSpan(
         lightstep.tracer._LightstepTracer(False, recorder),
         operation_name=str(i),
         context=SpanContext(
             trace_id=1000+i,
             span_id=2000+i),
         start_time=time.time())
コード例 #7
0
def dummy_basic_span(recorder, i):
    span = BasicSpan(
        lightstep.tracer._LightstepTracer(False, recorder, None),
        operation_name=str(i),
        context=SpanContext(trace_id=1000 + i, span_id=2000 + i),
        start_time=time.time() - 100,
    )
    span.finish()
    return span
コード例 #8
0
ファイル: __init__.py プロジェクト: hire-us/fan-backup
 def extract(self, carrier):
     # TODO: support ot-debug => override sampled to true
     # generate custom label
     try:
         kwargs = {'baggage': {}}
         for k, v in self.mapping.items():
             name, _, extract = v
             kwargs[k] = extract(carrier[name])
         return SpanContext(**kwargs)
     except Exception:
         pass
コード例 #9
0
 def finish(self, finish_time=None):
     if self.parent_id is None:
         self.tracer.cur_ctx = None
     else:
         # Set tracer context to the parent span
         pctx = SpanContext(span_id=self.parent_id,
                            trace_id=self.context.trace_id,
                            baggage={},
                            sampled=True)
         self.tracer.cur_ctx = pctx
     super(InstanaSpan, self).finish(finish_time)
コード例 #10
0
ファイル: __init__.py プロジェクト: hire-us/fan-backup
 def extract(self, carrier):
     self.log.debug('Run extract: {}'.format(carrier))
     try:
         kwargs = {'baggage': {}}
         for k, v in self.mapping.items():
             name, _, extract = v
             key = name if name in carrier else 'HTTP_{}'.format(name)
             # crash when no HTTP_OT_SPAN_ID => return None
             kwargs[k] = extract(carrier[key])
         return SpanContext(**kwargs)
     except Exception:
         pass
コード例 #11
0
    def extract(self, carrier):  # noqa
        try:
            if type(carrier) is dict or hasattr(carrier, "__dict__"):
                dc = carrier
            elif type(carrier) is list:
                dc = dict(carrier)
            else:
                raise ot.SpanContextCorruptedException()

            if field_name_trace_id in dc and field_name_span_id in dc:
                trace_id = util.header_to_id(dc[field_name_trace_id])
                span_id = util.header_to_id(dc[field_name_span_id])

            return SpanContext(span_id=span_id,
                               trace_id=trace_id,
                               baggage={},
                               sampled=True)

        except Exception as e:
            log.debug("extract error: ", str(e))
            return SpanContext()
コード例 #12
0
ファイル: tracer.py プロジェクト: Sandared/python-sensor
    def start_span(self,
                   operation_name=None,
                   child_of=None,
                   references=None,
                   tags=None,
                   start_time=None,
                   ignore_active_span=False):
        "Taken from BasicTracer so we can override generate_id calls to ours"

        start_time = time.time() if start_time is None else start_time

        # See if we have a parent_ctx in `references`
        parent_ctx = None
        if child_of is not None:
            parent_ctx = (
                child_of if isinstance(child_of, ot.SpanContext)
                else child_of.context)
        elif references is not None and len(references) > 0:
            # TODO only the first reference is currently used
            parent_ctx = references[0].referenced_context

        # retrieve the active SpanContext
        if not ignore_active_span and parent_ctx is None:
            scope = self.scope_manager.active
            if scope is not None:
                parent_ctx = scope.span.context

        # Assemble the child ctx
        gid = generate_id()
        ctx = SpanContext(span_id=gid)
        if parent_ctx is not None:
            if parent_ctx._baggage is not None:
                ctx._baggage = parent_ctx._baggage.copy()
            ctx.trace_id = parent_ctx.trace_id
            ctx.sampled = parent_ctx.sampled
        else:
            ctx.trace_id = gid
            ctx.sampled = self.sampler.sampled(ctx.trace_id)

        # Tie it all together
        span = InstanaSpan(self,
                           operation_name=operation_name,
                           context=ctx,
                           parent_id=(None if parent_ctx is None else parent_ctx.span_id),
                           tags=tags,
                           start_time=start_time)

        if operation_name in self.recorder.entry_spans:
            # For entry spans, add only a backtrace fingerprint
            self.__add_stack(span, limit=2)

        if operation_name in self.recorder.exit_spans:
            self.__add_stack(span)

        return span
コード例 #13
0
    def extract(self, carrier):
        if type(carrier) is not bytearray:
            raise InvalidCarrierException()
        serializedProto = standard_b64decode(carrier)
        state = BinaryCarrier()
        state.ParseFromString(bytes(serializedProto))
        baggage = {}
        for k in state.basic_ctx.baggage_items:
            baggage[k] = state.basic_ctx.baggage_items[k]

        return SpanContext(span_id=state.basic_ctx.span_id,
                           trace_id=state.basic_ctx.trace_id,
                           baggage=baggage,
                           sampled=state.basic_ctx.sampled)
コード例 #14
0
    def extract(self, carrier):
        if type(carrier) is not bytearray:
            raise InvalidCarrierException()
        m = memoryview(carrier)
        m, trace_id = _rstr(m)
        m, span_id = _rstr(m)
        sampled = struct.unpack('?', m[:1])[0]
        m = m[1:]
        bl = struct.unpack('>I', m[:4])[0]
        m = m[4:]
        baggage = {}
        for _ in range(bl):
            m, k = _rstr(m)
            m, v = _rstr(m)
            baggage[k] = v

        return SpanContext(span_id=span_id,
                           trace_id=trace_id,
                           baggage=baggage,
                           sampled=sampled)
コード例 #15
0
    def start_span(self,
                   operation_name=None,
                   child_of=None,
                   references=None,
                   tags=None,
                   start_time=None):
        "Taken from BasicTracer so we can override generate_id calls to ours"

        start_time = time.time() if start_time is None else start_time

        # See if we have a parent_ctx in `references`
        parent_ctx = None
        if child_of is not None:
            parent_ctx = (child_of if isinstance(child_of, ot.SpanContext) else
                          child_of.context)
        elif references is not None and len(references) > 0:
            # TODO only the first reference is currently used
            parent_ctx = references[0].referenced_context

        # Assemble the child ctx
        instana_id = generate_id()
        ctx = SpanContext(span_id=instana_id)
        if parent_ctx is not None:
            if parent_ctx._baggage is not None:
                ctx._baggage = parent_ctx._baggage.copy()
            ctx.trace_id = parent_ctx.trace_id
            ctx.sampled = parent_ctx.sampled
        else:
            ctx.trace_id = instana_id
            ctx.sampled = self.sampler.sampled(ctx.trace_id)

        # Tie it all together
        span = InstanaSpan(
            self,
            operation_name=operation_name,
            context=ctx,
            parent_id=(None if parent_ctx is None else parent_ctx.span_id),
            tags=tags,
            start_time=start_time)

        self.cur_ctx = span.context
        return span
コード例 #16
0
    def extract(self, carrier):  # noqa
        trace_id = None
        span_id = None

        try:
            if type(carrier) is dict or hasattr(carrier, "__getitem__"):
                dc = carrier
            elif hasattr(carrier, "__dict__"):
                dc = carrier.__dict__
            elif type(carrier) is list:
                dc = dict(carrier)
            else:
                raise ot.SpanContextCorruptedException()

            # Headers can exist in the standard X-Instana-T/S format or the alternate HTTP_X_INSTANA_T/S style
            # We do a case insensitive search to cover all possible variations of incoming headers.
            for key in dc.keys():
                lc_key = key.lower()

                if self.LC_HEADER_KEY_T == lc_key:
                    trace_id = header_to_id(dc[key])
                elif self.LC_HEADER_KEY_S == lc_key:
                    span_id = header_to_id(dc[key])

                elif self.ALT_LC_HEADER_KEY_T == lc_key:
                    trace_id = header_to_id(dc[key])
                elif self.ALT_LC_HEADER_KEY_S == lc_key:
                    span_id = header_to_id(dc[key])

            ctx = None
            if trace_id is not None and span_id is not None:
                ctx = SpanContext(span_id=span_id,
                                  trace_id=trace_id,
                                  baggage={},
                                  sampled=True)
            return ctx

        except Exception as e:
            logger.debug("extract error:", exc_info=True)
コード例 #17
0
 def extract(self, carrier):
     return SpanContext()
コード例 #18
0
    def extract(self, carrier):
        traceparent = None
        tracestate = None

        multiple_header_template = "Found more than one header value for {}"

        # https://www.w3.org/TR/2019/CR-trace-context-20190813/#header-name

        trace_context_free_carrier = {}

        for key, value in carrier.items():

            lower_key = key.lower()

            # The document requires that the headers be accepted regardless of
            # the case of their characters. This means that the keys of carrier
            # may contain 2 or more strings that match traceparent or
            # tracestate when the case of the characters of such strings is
            # ignored. The document does not specify what is to be done in such
            # a situation, this implementation will raise an exception.
            if lower_key == _TRACEPARENT:

                if traceparent is None:
                    traceparent = value

                else:
                    raise SpanContextCorruptedException(
                        multiple_header_template.format(_TRACEPARENT))

            elif lower_key == _TRACESTATE:

                if tracestate is None:
                    tracestate = value

                else:
                    raise SpanContextCorruptedException(
                        multiple_header_template.format(_TRACEPARENT))

            else:
                trace_context_free_carrier[key] = value

        if traceparent is None:
            # https://www.w3.org/TR/trace-context/#no-traceparent-received
            _LOG.warning("No traceparent was received")
            return SpanContext(trace_id=getrandbits(128),
                               span_id=getrandbits(64))

        else:

            version_match = _VERSION.match(traceparent)

            if version_match is None:
                # https://www.w3.org/TR/2019/CR-trace-context-20190813/#versioning-of-traceparent
                _LOG.warning("Unable to parse version from traceparent")
                return SpanContext(trace_id=getrandbits(128),
                                   span_id=getrandbits(64))

            # https://www.w3.org/TR/2019/CR-trace-context-20190813/#version
            version = version_match.group("version")
            if version == "ff":
                _LOG.warning("Forbidden value of 255 found in version")
                return SpanContext(trace_id=getrandbits(128),
                                   span_id=getrandbits(64))

            # https://www.w3.org/TR/2019/CR-trace-context-20190813/#versioning-of-traceparent
            if int(version, 16) > 0:

                if len(traceparent) < 55:
                    _LOG.warning(
                        "traceparent shorter than 55 characters found")
                    return SpanContext(trace_id=getrandbits(128),
                                       span_id=getrandbits(64))

                remainder_match = _FUTURE_VERSION_REMAINDER.match(traceparent)

            else:
                remainder_match = _00_VERSION_REMAINDER.match(traceparent)

            if remainder_match is None:
                # This will happen if any of the trace-id, parent-id or
                # trace-flags fields contains non-allowed characters.
                # The document specifies that traceparent must be ignored if
                # these kind of characters appear in trace-id and parent-id,
                # but it does not specify what to do if they appear in
                # trace-flags.
                # Here it is assumed that traceparent is to be ignored also if
                # non-allowed characters are present in trace-flags too.
                _LOG.warning(
                    "Received an invalid traceparent: {}".format(traceparent))
                return SpanContext(trace_id=getrandbits(128),
                                   span_id=getrandbits(64))

            # https://www.w3.org/TR/2019/CR-trace-context-20190813/#trace-id
            trace_id = remainder_match.group("trace_id")
            if trace_id == 32 * "0":
                _LOG.warning(
                    "Forbidden value of {} found in trace-id".format(trace_id))
                return SpanContext(trace_id=getrandbits(128),
                                   span_id=getrandbits(64))

            # https://www.w3.org/TR/2019/CR-trace-context-20190813/#parent-id
            parent_id = remainder_match.group("parent_id")
            if parent_id == 16 * "0":
                _LOG.warning("Forbidden value of {}"
                             " found in parent-id".format(parent_id))
                return SpanContext(trace_id=getrandbits(128),
                                   span_id=getrandbits(64))

            # https://www.w3.org/TR/2019/CR-trace-context-20190813/#trace-flags
            raw_trace_flags = remainder_match.group("trace_flags")

            trace_flags = []

            for index, bit_flag in enumerate(
                    zip(
                        bin(int(raw_trace_flags, 16))[2:].zfill(8),
                        # https://www.w3.org/TR/2019/CR-trace-context-20190813/#other-flags
                        # Flags can be added in the next list as the document
                        # progresses and they get defined. This list represents the
                        # 8 bits that are available in trace-flags and their
                        # respective meaning.
                        [None, None, None, None, None, None, None, "sampled"
                         ])):
                bit, flag = bit_flag

                if int(bit):
                    if flag is None:
                        warn("Invalid flag set at bit {}".format(index))
                        trace_flags.append("0")

                    else:
                        trace_flags.append("1")

                else:
                    trace_flags.append("0")

            trace_context_free_carrier["trace-flags"] = int(
                "".join(trace_flags), 2)

            if tracestate is not None:

                tracestate_dictionary = OrderedDict()

                for counter, list_member in enumerate(tracestate.split(",")):
                    # https://www.w3.org/TR/trace-context/#tracestate-header-field-values
                    if counter > 31:
                        _LOG.warning(
                            "More than 32 list-members "
                            "found in tracestate {}".format(tracestate))
                        break

                    # https://www.w3.org/TR/trace-context/#tracestate-header-field-values
                    if _BLANK.match(list_member):
                        _LOG.debug("Ignoring empty tracestate list-member")
                        continue

                    key_value = _KEY_VALUE.match(list_member)

                    if key_value is None:
                        _LOG.warning("Invalid key/value pair found: {}".format(
                            key_value))
                        break

                    key, value = key_value.groups()

                    if key in tracestate_dictionary.keys():
                        _LOG.warning(
                            "Duplicate tracestate key found: {}".format(key))
                        break

                    tracestate_dictionary[key] = value

                else:
                    trace_context_free_carrier[_TRACESTATE] = ",".join([
                        "{0}={1}".format(key, value)
                        for key, value in tracestate_dictionary.items()
                    ])

        return SpanContext(trace_id=int(trace_id, 16),
                           span_id=int(parent_id, 16),
                           baggage=trace_context_free_carrier)
コード例 #19
0
def test_exception_formatting(recorder):
    mock_connection = MockConnection()
    mock_connection.open()

    assert len(recorder._span_records) == 0

    span = BasicSpan(
        lightstep.tracer._LightstepTracer(False, recorder, None),
        operation_name="exception span",
        context=SpanContext(trace_id=1000, span_id=2000),
        start_time=time.time() - 100,
    )
    span.log_kv({ERROR_KIND: AttributeError})
    span.finish()
    assert len(recorder._span_records) == 1
    assert recorder.flush(mock_connection)
    spans = recorder.converter.get_span_records(mock_connection.reports[0])
    if hasattr(spans[0], "log_records"):
        assert len(spans[0].log_records) == 1
        assert len(spans[0].log_records[0].fields) == 1
        assert spans[0].log_records[0].fields[0] == ttypes.KeyValue(
            Key="error.kind", Value="AttributeError")
    else:
        assert len(spans[0].logs) == 1
        assert len(spans[0].logs[0].fields) == 1
        assert spans[0].logs[0].fields[0].key == "error.kind"
        assert spans[0].logs[0].fields[0].string_value == "AttributeError"

    span = BasicSpan(
        lightstep.tracer._LightstepTracer(False, recorder, None),
        operation_name="exception span",
        context=SpanContext(trace_id=1000, span_id=2000),
        start_time=time.time() - 100,
    )

    try:
        raise Exception
    except Exception:  # pylint: disable=broad-except
        exc_type, exc_value, exc_tb = sys.exc_info()
        span.log_kv({
            STACK: exc_tb,
            ERROR_KIND: exc_type,
            ERROR_OBJECT: exc_value
        })

    span.finish()
    assert len(recorder._span_records) == 1
    assert recorder.flush(mock_connection)
    spans = recorder.converter.get_span_records(mock_connection.reports[1])

    if hasattr(spans[0], "log_records"):
        assert len(spans[0].log_records) == 1
        assert len(spans[0].log_records[0].fields) == 3
        for field in spans[0].log_records[0].fields:
            if field.Key == "stack":
                assert "Traceback (most recent call last):" in field.Value
            elif field.Key == "error.kind":
                assert field.Value == "Exception"
            elif field.Key == "error.object":
                assert field.Value == ""
            else:
                raise AttributeError("unexpected field: %s".format(field.Key))
    else:
        assert len(spans[0].logs) == 1
        assert len(spans[0].logs[0].fields) == 3

        for field in spans[0].logs[0].fields:
            if field.key == "stack":
                assert "Traceback (most recent call last):" in field.string_value
            elif field.key == "error.kind":
                assert field.string_value == "Exception"
            elif field.key == "error.object":
                assert field.string_value == ""
            else:
                raise AttributeError("unexpected field: %s".format(field.key))
コード例 #20
0
 def dummy_basic_span(self, recorder, i):
     return BasicSpan(zipkin_ot.tracer._OpenZipkinTracer(recorder),
                      operation_name=str(i),
                      context=SpanContext(trace_id=1000 + i,
                                          span_id=2000 + i),
                      start_time=time.time())
コード例 #21
0
    def extract(self, carrier):

        case_insensitive_carrier = {}
        for key, value in carrier.items():
            for b3_key in [
                    _SINGLE_HEADER,
                    _TRACEID,
                    _SPANID,
                    _PARENTSPANID,
                    _SAMPLED,
                    _FLAGS,
            ]:
                if key.lower() == b3_key:
                    case_insensitive_carrier[b3_key] = value
                else:
                    case_insensitive_carrier[key] = value

        carrier = case_insensitive_carrier
        baggage = {}

        if _SINGLE_HEADER in carrier.keys():
            fields = carrier.pop(_SINGLE_HEADER).split("-", 4)
            baggage.update(carrier)
            len_fields = len(fields)
            if len_fields == 1:
                sampled = fields[0]
            elif len_fields == 2:
                traceid, spanid = fields
            elif len_fields == 3:
                traceid, spanid, sampled = fields
            else:
                traceid, spanid, sampled, parent_spanid = fields
                baggage[_PARENTSPANID] = int(parent_spanid, 16)
            if sampled == "d":
                baggage[_FLAGS] = 1
            else:
                baggage[_SAMPLED] = int(sampled, 16)
        else:
            traceid = carrier.pop(_TRACEID, None)
            spanid = carrier.pop(_SPANID, None)
            parentspanid = carrier.pop(_PARENTSPANID, None)
            sampled = carrier.pop(_SAMPLED, None)
            flags = carrier.pop(_FLAGS, None)

            if sampled is flags is (traceid and spanid) is None:

                raise SpanContextCorruptedException()

            if parentspanid is not None:
                baggage[_PARENTSPANID] = int(parentspanid, 16)

            if flags == 1:
                baggage[_FLAGS] = flags
                if sampled is not None:
                    warn("x-b3-flags: 1 implies x-b3-sampled: 1, ignoring "
                         "the received value of x-b3-sampled")
            elif sampled is not None:
                baggage[_SAMPLED] = sampled

            baggage.update(carrier)

            if baggage == OTSpanContext.EMPTY_BAGGAGE:
                baggage = None

        return SpanContext(trace_id=int(traceid, 16),
                           span_id=int(spanid, 16),
                           baggage=baggage)