def test_context_to_readable_headers(self): for url_encoding in [False, True]: codec = TextCodec(url_encoding=url_encoding, trace_id_header='Trace_ID', baggage_header_prefix='Trace-Attr-') ctx = SpanContext(trace_id=256, span_id=127, parent_id=None, flags=1) carrier = {} codec.inject(ctx, carrier) assert carrier == {'trace-id': '100:7f:0:1'} ctx._baggage = { 'fry': 'Leela', 'bender': 'Countess de la Roca', } carrier = {} codec.inject(ctx, carrier) if url_encoding: assert carrier == { 'trace-id': '100:7f:0:1', 'trace-attr-bender': 'Countess%20de%20la%20Roca', 'trace-attr-fry': 'Leela' } else: assert carrier == { 'trace-id': '100:7f:0:1', 'trace-attr-bender': 'Countess de la Roca', 'trace-attr-fry': 'Leela' }
def test_with_baggage_items(): baggage1 = {'x': 'y'} ctx1 = SpanContext(trace_id=1, span_id=2, parent_id=3, flags=1, baggage=baggage1) ctx2 = ctx1.with_baggage_item('a', 'b') assert ctx1.trace_id == ctx2.trace_id assert ctx1.span_id == ctx2.span_id assert ctx1.parent_id == ctx2.parent_id assert ctx1.flags == ctx2.flags assert ctx1.baggage != ctx2.baggage baggage1['a'] = 'b' assert ctx1.baggage == ctx2.baggage
def test_context_to_readable_headers(self): for url_encoding in [False, True]: codec = TextCodec(url_encoding=url_encoding, trace_id_header='Trace_ID', baggage_header_prefix='Trace-Attr-') ctx = SpanContext(trace_id=256, span_id=127, parent_id=None, flags=1) carrier = {} codec.inject(ctx, carrier) assert carrier == {'trace-id': '100:7f:0:1'} ctx._baggage = { 'fry': u'Leela', 'bender': 'Countess de la Roca', b'key1': bytes(chr(255)), u'key2-caf\xe9': 'caf\xc3\xa9', u'key3': u'caf\xe9', 'key4-caf\xc3\xa9': 'value', } carrier = {} codec.inject(ctx, carrier) # NB: the reverse transformation is not exact, e.g. this fails: # assert ctx._baggage == codec.extract(carrier)._baggage # But fully supporting lossless Unicode baggage is not the goal. if url_encoding: assert carrier == { 'trace-id': '100:7f:0:1', 'trace-attr-bender': 'Countess%20de%20la%20Roca', 'trace-attr-fry': 'Leela', 'trace-attr-key1': '%FF', 'trace-attr-key2-caf\xc3\xa9': 'caf%C3%A9', 'trace-attr-key3': 'caf%C3%A9', 'trace-attr-key4-caf\xc3\xa9': 'value', }, 'with url_encoding = %s' % url_encoding for key, val in six.iteritems(carrier): assert isinstance(key, str) or isinstance(key, newstr) assert isinstance(val, str) or isinstance( val, newstr), '%s' % type(val) else: assert carrier == { 'trace-id': '100:7f:0:1', 'trace-attr-bender': 'Countess de la Roca', 'trace-attr-fry': 'Leela', 'trace-attr-key1': '\xff', u'trace-attr-key2-caf\xe9': 'caf\xc3\xa9', u'trace-attr-key3': u'caf\xe9', 'trace-attr-key4-caf\xc3\xa9': 'value', }, 'with url_encoding = %s' % url_encoding
def test_baggage_logs(): mock_tracer = mock.MagicMock() mock_tracer.max_tag_value_length = 100 ctx = SpanContext(trace_id=1, span_id=2, parent_id=None, flags=1) span = Span(context=ctx, operation_name='x', tracer=mock_tracer) span.set_baggage_item('x', 'a') assert span.get_baggage_item('x') == 'a' assert len(span.logs) == 1 assert _fields_to_dict(span.logs[0]) == { 'event': 'baggage', 'key': 'x', 'value': 'a', } span.set_baggage_item('x', 'b') # override assert span.get_baggage_item('x') == 'b' assert len(span.logs) == 2 assert _fields_to_dict(span.logs[1]) == { 'event': 'baggage', 'key': 'x', 'value': 'b', 'override': 'true', } span.set_baggage_item('x', None) # deletion assert span.get_baggage_item('x') is None assert len(span.logs) == 3 assert _fields_to_dict(span.logs[2]) == { 'event': 'baggage', 'key': 'x', 'value': 'None', 'override': 'true' }
def serialize(span_id): parent_ctx = SpanContext(trace_id=span_id, span_id=span_id, parent_id=0, flags=1) parent = Span(context=parent_ctx, operation_name='x', tracer=tracer) span = tracer.start_span(operation_name='x', references=child_of(parent.context)) span.finish() _marshall_span(span)
def test_with_baggage_items(): baggage1 = {'x': 'y'} ctx1 = SpanContext(trace_id=1, span_id=2, parent_id=3, flags=1, baggage=baggage1) ctx2 = ctx1.with_baggage_item('a', 'b') assert ctx1.trace_id == ctx2.trace_id assert ctx1.span_id == ctx2.span_id assert ctx1.parent_id == ctx2.parent_id assert ctx1.flags == ctx2.flags assert ctx1.baggage != ctx2.baggage baggage1['a'] = 'b' assert ctx1.baggage == ctx2.baggage ctx3 = ctx2.with_baggage_item('a', None) assert ctx2.baggage != ctx3.baggage baggage1.pop('a') assert ctx3.baggage == baggage1
def test_context_to_readable_headers(self): for url_encoding in [False, True]: codec = TextCodec( url_encoding=url_encoding, trace_id_header='Trace_ID', baggage_header_prefix='Trace-Attr-') ctx = SpanContext( trace_id=256, span_id=127, parent_id=None, flags=1 ) carrier = {} codec.inject(ctx, carrier) assert carrier == {'trace-id': '100:7f:0:1'} ctx._baggage = { 'bender': 'Countess de la Roca', 'fry': u'Leela', b'key1': bytes(chr(75)) if six.PY2 else bytes([75]), u'key2': 'cafe', u'key3': u'\U0001F47E', } carrier = {} codec.inject(ctx, carrier) # NB: the reverse transformation is not exact, e.g. this fails: # assert ctx._baggage == codec.extract(carrier)._baggage # But fully supporting lossless Unicode baggage is not the goal. if url_encoding: assert carrier == { 'trace-id': '100:7f:0:1', 'trace-attr-bender': 'Countess%20de%20la%20Roca', 'trace-attr-fry': 'Leela', 'trace-attr-key1': 'K', 'trace-attr-key2': 'cafe', 'trace-attr-key3': '%F0%9F%91%BE', }, 'with url_encoding = %s' % url_encoding for key, val in six.iteritems(carrier): assert isinstance(key, str) assert isinstance(val, str), '%s' % type(val) else: assert carrier == { 'trace-id': '100:7f:0:1', 'trace-attr-bender': 'Countess de la Roca', 'trace-attr-fry': 'Leela', 'trace-attr-key1': 'K', u'trace-attr-key2': 'cafe', 'trace-attr-key3': u'\U0001F47E', }, 'with url_encoding = %s' % url_encoding
def _new_span(name): tracer = FakeTrace(ip_address='127.0.0.1', service_name='reporter_test') ctx = SpanContext(trace_id=1, span_id=1, parent_id=None, flags=1) span = Span(context=ctx, tracer=tracer, operation_name=name) span.start_time = time.time() span.end_time = span.start_time + 0.001 # 1ms return span
async def req(c): for ii in range(100): ctx = SpanContext(trace_id=randomnize.getrandbits(32), span_id=randomnize.getrandbits(32), parent_id=0, flags=1) span = Span(context=ctx, operation_name='RootSpan', tracer=tracer) span.log_kv({ 'event': 'RootSpan', }) # with tracer.start_span('TestSpan') as span: # # span.log_kv({'span.trace_id': span.trace_id, # 'span.span_id': span.span_id, # 'span.parent_id': span.parent_id, # 'span.operation_name': span.operation_name, # }) # # # ctx = SpanContext(trace_id=child_span.trace_id, span_id=span_id1, parent_id=child_span.span_id, flags=1) # # span1 = Span(context=ctx, operation_name='ChildSpanChildSpan', tracer=tracer) # # span1.log_kv({'event': 'ChildSpanChildSpan', }) # # # t1 = time.time() # # try: # # r = await c.SayHello( # # helloworld_pb2.HelloRequest(name='test11', spaninfo=get_span_str(span))) # # # print("Greeting:", r.message) # # except Exception as e: # # pass # # # # t2 = time.time() # # print(t2 - t1) # # span.log_kv({'span.trace_id': span.trace_id, # 'span.span_id': span.span_id, # 'span.parent_id': span.parent_id, # 'span.operation_name': span.operation_name, # }) t1 = time.time() try: r = await c.SayHello( helloworld_pb2.HelloRequest(name='test11', spaninfo=get_span_str(span))) # print("Greeting:", r.message) except Exception as e: pass t2 = time.time() print(t2 - t1) span.log_kv({ 'event': t2 - t1, }) span.finish()
def serialize(trace_id, span_id): """Checks that there are no exceptions during marshalling.""" parent_ctx = SpanContext(trace_id=trace_id, span_id=span_id, parent_id=0, flags=1) parent = Span(context=parent_ctx, operation_name='x', tracer=tracer) span = tracer.start_span(operation_name='x', references=child_of(parent.context)) span.finish() _marshall_span(span)
def test_zipkin_b3_codec_extract_injected(self): codec = B3Codec() ctx = SpanContext(trace_id=256, span_id=127, parent_id=None, flags=0) span = Span(context=ctx, operation_name='x', tracer=None, start_time=1) carrier = {} codec.inject(span_context=span, carrier=carrier) extracted = codec.extract(carrier) assert extracted.trace_id == ctx.trace_id assert extracted.span_id == ctx.span_id assert extracted.parent_id == ctx.parent_id assert extracted.flags == ctx.flags
def test_zipkin_codec_inject(self): codec = ZipkinCodec() with self.assertRaises(InvalidCarrierException): codec.inject(span_context=None, carrier=[]) ctx = SpanContext(trace_id=256, span_id=127, parent_id=None, flags=1) span = Span(context=ctx, operation_name='x', tracer=None, start_time=1) carrier = {} codec.inject(span_context=span, carrier=carrier) assert carrier == {'span_id': 127, 'parent_id': None, 'trace_id': 256, 'traceflags': 1}
def test_tracer_throttler(): tracer = Tracer(service_name='x', reporter=mock.MagicMock(), sampler=mock.MagicMock(), throttler=mock.MagicMock()) tracer.throttler.is_allowed.return_value = True assert tracer.is_debug_allowed() tracer.throttler.is_allowed.return_value = False assert not tracer.is_debug_allowed() debug_span_context = SpanContext.with_debug_id('debug-id') span = tracer.start_span('test-operation', child_of=debug_span_context) assert not span.is_debug()
def test_inject_with_128bit_trace_id(tracer, fmt, carrier, get_trace_id): tracer_128bit = Tracer(service_name='test', reporter=InMemoryReporter(), sampler=ConstSampler(True), generate_128bit_trace_id=True) for tracer in [tracer, tracer_128bit]: length = tracer.max_trace_id_bits / 4 trace_id = (1 << 64) - 1 if length == 16 else (1 << 128) - 1 ctx = SpanContext(trace_id=trace_id, span_id=127, parent_id=None, flags=1) span = Span(ctx, operation_name='test-%s' % fmt, tracer=None, start_time=1) tracer.inject(span, fmt, carrier) assert len(get_trace_id(carrier)) == length # test if the trace_id arrived on wire remains same even if # the tracer is configured for 64bit ids or 128bit ids ctx = SpanContext(trace_id=(1 << 128) - 1, span_id=127, parent_id=None, flags=0) span = tracer.start_span('test-%s' % fmt, child_of=ctx) carrier = dict() tracer.inject(span, fmt, carrier) assert len(get_trace_id(carrier)) == 32 ctx = SpanContext(trace_id=(1 << 64) - 1, span_id=127, parent_id=None, flags=0) span = tracer.start_span('test-%s' % fmt, child_of=ctx) carrier = dict() tracer.inject(span, fmt, carrier) assert len(get_trace_id(carrier)) == 16
def test_baggage_logs(): ctx = SpanContext(trace_id=1, span_id=2, parent_id=None, flags=1) span = Span(context=ctx, operation_name='x', tracer=None) span.set_baggage_item('x', 'a') assert span.get_baggage_item('x') == 'a' assert len(span.logs) == 1 assert span.logs[ 0].value == '{"value": "a", "event": "baggage", "key": "x"}' span.set_baggage_item('x', 'b') # override assert span.get_baggage_item('x') == 'b' assert len(span.logs) == 2 assert span.logs[ 1].value == '{"override": "true", "value": "b", "event": "baggage", "key": "x"}'
def extract(self, carrier): span_context = SpanContext(trace_id=None, span_id=None, parent_id=None, flags=0) for k, v in six.iteritems(carrier): k = k.lower() extractor = self._extractors.get(k) if six.callable(extractor) and v is not None: extractor(v, span_context) if span_context.trace_id is None or span_context.span_id is None: return None return span_context
def test_zipkin_b3_codec_inject(self): codec = B3Codec() with self.assertRaises(InvalidCarrierException): codec.inject(span_context=None, carrier=[]) ctx = SpanContext(trace_id=256, span_id=127, parent_id=None, flags=1) span = Span(context=ctx, operation_name='x', tracer=None, start_time=1) carrier = {} codec.inject(span_context=span, carrier=carrier) assert carrier == { 'X-B3-SpanId': format(127, 'x').zfill(16), 'X-B3-TraceId': format(256, 'x').zfill(16), 'X-B3-Flags': '1' }
def decode_msg_data(data): # https://github.com/jaegertracing/jaeger-client-go/blob/master/propagation.go trace_id_high = int.from_bytes(data[:8], byteorder='big') trace_id_low = int.from_bytes(data[8:16], byteorder='big') span_id = int.from_bytes(data[16:24], byteorder='big') parent_id = int.from_bytes(data[24:32], byteorder='big') flags = data[32] msg = data[37:].decode('utf-8') # print('trace_id_high={}, trace_id_low={}, span_id={}, parent_id={}, flags={}'.format( \ # hex(trace_id_high), hex(trace_id_low), hex(span_id), hex(parent_id), hex(flags))) return SpanContext(trace_id=trace_id_low, span_id=span_id, parent_id=parent_id, flags=flags), msg
def test_baggage(): ctx = SpanContext(trace_id=1, span_id=2, parent_id=None, flags=1) span = Span(context=ctx, operation_name='x', tracer=None) assert span.get_baggage_item('x') is None span.set_baggage_item('x', 'y').\ set_baggage_item('z', 'why') assert span.get_baggage_item('x') == 'y' assert span.get_baggage_item('z') == 'why' assert span.get_baggage_item('tt') is None assert len(span.context.baggage) == 2 span.set_baggage_item('x', 'b') # override assert span.get_baggage_item('x') == 'b' assert len(span.context.baggage) == 2 span.set_baggage_item('X_y', '123') assert span.get_baggage_item('X_y') == '123' assert span.get_baggage_item('x-Y') is None
def test_traceback_cut(): """Test that a traceback is cut off at max_tag_value_length""" mock_tracer = mock.MagicMock() mock_tracer.max_tag_value_length = 300 mock_tracer.max_traceback_length = 5 context = SpanContext(trace_id=1, span_id=2, parent_id=None, flags=1) span = Span(context=context, operation_name='traceback_test', tracer=mock_tracer) try: with span: raise ValueError('Something unexpected happened!') except ValueError: fields_dict = {field.key: field.vStr for field in span.logs[0].fields} assert 'stack' in fields_dict stack_message = fields_dict['stack'] assert stack_message == ' Fil'
def test_baggage(): mock_tracer = mock.MagicMock() mock_tracer.max_tag_value_length = 100 ctx = SpanContext(trace_id=1, span_id=2, parent_id=None, flags=1) span = Span(context=ctx, operation_name='x', tracer=mock_tracer) assert span.get_baggage_item('x') is None span.set_baggage_item('x', 'y').\ set_baggage_item('z', 'why') assert span.get_baggage_item('x') == 'y' assert span.get_baggage_item('z') == 'why' assert span.get_baggage_item('tt') is None assert len(span.context.baggage) == 2 span.set_baggage_item('x', 'b') # override assert span.get_baggage_item('x') == 'b' assert len(span.context.baggage) == 2 span.set_baggage_item('X_y', '123') assert span.get_baggage_item('X_y') == '123' assert span.get_baggage_item('x-Y') is None
def test_is_rpc(): mock_tracer = mock.MagicMock() mock_tracer.max_tag_value_length = 100 ctx = SpanContext(trace_id=1, span_id=2, parent_id=None, flags=1) span = Span(context=ctx, operation_name='x', tracer=mock_tracer) assert span.is_rpc() is False assert span.is_rpc_client() is False span = Span(context=ctx, operation_name='x', tracer=mock_tracer) span.set_tag(ext_tags.SPAN_KIND, ext_tags.SPAN_KIND_RPC_SERVER) assert span.is_rpc() is True assert span.is_rpc_client() is False span = Span(context=ctx, operation_name='x', tracer=mock_tracer) span.set_tag(ext_tags.SPAN_KIND, ext_tags.SPAN_KIND_RPC_CLIENT) assert span.is_rpc() is True assert span.is_rpc_client() is True
def test_baggage_logs(): mock_tracer = mock.MagicMock() mock_tracer.max_tag_value_length = 100 ctx = SpanContext(trace_id=1, span_id=2, parent_id=None, flags=1) span = Span(context=ctx, operation_name='x', tracer=mock_tracer) span.set_baggage_item('x', 'a') assert span.get_baggage_item('x') == 'a' assert len(span.logs) == 1 assert _fields_to_dict(span.logs[0]) == { "event": "baggage", "key": "x", "value": "a", } span.set_baggage_item('x', 'b') # override assert span.get_baggage_item('x') == 'b' assert len(span.logs) == 2 assert _fields_to_dict(span.logs[1]) == { "event": "baggage", "key": "x", "value": "b", "override": "true", }
def test_traceback(): """Test that a traceback is logged with both location and message""" mock_tracer = mock.MagicMock() mock_tracer.max_tag_value_length = 300 mock_tracer.max_traceback_length = 300 context = SpanContext(trace_id=1, span_id=2, parent_id=None, flags=1) span = Span(context=context, operation_name='traceback_test', tracer=mock_tracer) try: with span: raise ValueError('Something unexpected happened!') except ValueError: fields_dict = {field.key: field.vStr for field in span.logs[0].fields} assert 'stack' in fields_dict stack_message = fields_dict['stack'] stack_message_lines = stack_message.splitlines() assert len(stack_message_lines) == 2 assert stack_message_lines[0].startswith(' File ') assert stack_message_lines[1] == \ " raise ValueError('Something unexpected happened!')"
def start_span(self, operation_name=None, child_of=None, references=None, tags=None, start_time=None): """ Start and return a new Span representing a unit of work. :param operation_name: name of the operation represented by the new span from the perspective of the current service. :param child_of: shortcut for 'child_of' reference :param references: (optional) either a single Reference object or a list of Reference objects that identify one or more parent SpanContexts. (See the Reference documentation for detail) :param tags: optional dictionary of Span Tags. The caller gives up ownership of that dictionary, because the Tracer may use it as-is to avoid extra data copying. :param start_time: an explicit Span start time as a unix timestamp per time.time() :return: Returns an already-started Span instance. """ parent = child_of if references: if isinstance(references, list): # TODO(XXX) only the first reference is currently used references = references[0] parent = references.referenced_context # allow Span to be passed as reference, not just SpanContext if isinstance(parent, Span): parent = parent.context rpc_server = tags and \ tags.get(ext_tags.SPAN_KIND) == ext_tags.SPAN_KIND_RPC_SERVER if parent is None or parent.is_debug_id_container_only: trace_id = self.random_trace_id() span_id = self.random_id() parent_id = None flags = 0 baggage = None if parent is None: sampled, sampler_tags = \ self.sampler.is_sampled(trace_id, operation_name) if sampled: flags = SAMPLED_FLAG tags = tags or {} for k, v in six.iteritems(sampler_tags): tags[k] = v else: # have debug id flags = SAMPLED_FLAG | DEBUG_FLAG tags = tags or {} tags[self.debug_id_header] = parent.debug_id else: trace_id = parent.trace_id if rpc_server and self.one_span_per_rpc: # Zipkin-style one-span-per-RPC span_id = parent.span_id parent_id = parent.parent_id else: span_id = self.random_id() parent_id = parent.span_id flags = parent.flags baggage = dict(parent.baggage) span_ctx = SpanContext(trace_id=trace_id, span_id=span_id, parent_id=parent_id, flags=flags, baggage=baggage) span = Span(context=span_ctx, tracer=self, operation_name=operation_name, tags=tags, start_time=start_time) if (rpc_server or not parent_id) and (flags & SAMPLED_FLAG): # this is a first-in-process span, and is sampled for k, v in six.iteritems(self.tags): span.set_tag(k, v) self._emit_span_metrics(span=span, join=rpc_server) return span
def test_is_debug_id_container_only(): ctx = SpanContext.with_debug_id('value1') assert ctx.is_debug_id_container_only assert ctx.debug_id == 'value1' ctx = SpanContext(trace_id=1, span_id=2, parent_id=3, flags=1) assert not ctx.is_debug_id_container_only
def test_span_to_string(tracer): tracer.service_name = 'unittest' ctx = SpanContext(trace_id=1, span_id=1, parent_id=1, flags=1) span = Span(context=ctx, operation_name='crypt', tracer=tracer) assert '%s' % span == '1:1:1:1 unittest.crypt'
with tracer.start_span('TestSpan') as span: span.log_kv({'span.trace_id': span.trace_id, 'span.span_id': span.span_id, 'span.parent_id': span.parent_id, 'span.operation_name': span.operation_name, }) with tracer.start_span('ChildSpan', child_of=span) as child_span: child_span.log_kv({'span.trace_id': child_span.trace_id, 'child_span.span_id': child_span.span_id, 'child_span.parent_id': child_span.parent_id, 'child_span.operation_name': child_span.operation_name, }) ctx = SpanContext(trace_id=child_span.trace_id, span_id=span_id1, parent_id=child_span.span_id, flags=1) span1 = Span(context=ctx, operation_name='ChildSpanChildSpan', tracer=tracer) span1.log_kv({'event': 'ChildSpanChildSpan', }) span1.finish() child_span.log_kv({'span.trace_id': child_span.trace_id, 'child_span.span_id': child_span.span_id, 'child_span.parent_id': child_span.parent_id, 'child_span.operation_name': child_span.operation_name, }) span.log_kv({'span.trace_id': span.trace_id, 'span.span_id': span.span_id, 'span.parent_id': span.parent_id, 'span.operation_name': span.operation_name,
def test_parent_id_to_none(): ctx1 = SpanContext(trace_id=1, span_id=2, parent_id=0, flags=1) assert ctx1.parent_id is None