def test_links(self): other_context1 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), ) other_context2 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), ) other_context3 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), ) links = [ trace_api.Link(other_context1), trace_api.Link(other_context2, {"name": "neighbor"}), trace_api.Link(other_context3, {"component": "http"}), ] with self.tracer.start_as_current_span("root", links=links) as root: self.assertEqual(len(root.links), 3) self.assertEqual(root.links[0].context.trace_id, other_context1.trace_id) self.assertEqual(root.links[0].context.span_id, other_context1.span_id) self.assertEqual(root.links[0].attributes, {}) self.assertEqual(root.links[1].context.trace_id, other_context2.trace_id) self.assertEqual(root.links[1].context.span_id, other_context2.span_id) self.assertEqual(root.links[1].attributes, {"name": "neighbor"}) self.assertEqual(root.links[2].context.span_id, other_context3.span_id) self.assertEqual(root.links[2].attributes, {"component": "http"})
def test_links(self): ids_generator = trace_api.RandomIdsGenerator() other_context1 = trace_api.SpanContext( trace_id=ids_generator.generate_trace_id(), span_id=ids_generator.generate_span_id(), is_remote=False, ) other_context2 = trace_api.SpanContext( trace_id=ids_generator.generate_trace_id(), span_id=ids_generator.generate_span_id(), is_remote=False, ) links = ( trace_api.Link(other_context1), trace_api.Link(other_context2, {"name": "neighbor"}), ) with self.tracer.start_as_current_span("root", links=links) as root: self.assertEqual(len(root.links), 2) self.assertEqual( root.links[0].context.trace_id, other_context1.trace_id ) self.assertEqual( root.links[0].context.span_id, other_context1.span_id ) self.assertEqual(root.links[0].attributes, None) self.assertEqual( root.links[1].context.trace_id, other_context2.trace_id ) self.assertEqual( root.links[1].context.span_id, other_context2.span_id ) self.assertEqual(root.links[1].attributes, {"name": "neighbor"})
def test_span_environment_limits(self): reload(trace) tracer = new_tracer() id_generator = RandomIdGenerator() some_links = [ trace_api.Link( trace_api.SpanContext( trace_id=id_generator.generate_trace_id(), span_id=id_generator.generate_span_id(), is_remote=False, ) ) for _ in range(100) ] with pytest.raises(ValueError): with tracer.start_as_current_span("root", links=some_links): pass with tracer.start_as_current_span("root") as root: for idx in range(100): root.set_attribute("my_attribute_{}".format(idx), 0) root.add_event("my_event_{}".format(idx)) self.assertEqual(len(root.attributes), 10) self.assertEqual(len(root.events), 20)
def get_span_with_dropped_attributes_events_links(): attributes = {} for index in range(130): attributes[f"key{index}"] = [f"value{index}"] links = [] for index in range(129): links.append( trace_api.Link( trace_sdk._Span( name=f"span{index}", context=trace_api.INVALID_SPAN_CONTEXT, attributes=attributes, ).get_span_context(), attributes=attributes, )) tracer = new_tracer( span_limits=trace_sdk.SpanLimits(), resource=Resource(attributes=attributes), ) with tracer.start_as_current_span("span", links=links, attributes=attributes) as span: for index in range(131): span.add_event(f"event{index}", attributes=attributes) return span
def add_link( self, link_target_context: "trace_api.SpanContext", attributes: types.Attributes = None, ) -> None: if attributes is None: attributes = Span.empty_attributes self.add_lazy_link(trace_api.Link(link_target_context, attributes))
def test_links(self): other_context1 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), is_remote=False, ) other_context2 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), is_remote=False, ) other_context3 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), is_remote=False, ) def get_link_attributes(): return {"component": "http"} links = ( trace_api.Link(other_context1), trace_api.Link(other_context2, {"name": "neighbor"}), trace_api.LazyLink(other_context3, get_link_attributes), ) with self.tracer.start_as_current_span("root", links=links) as root: self.assertEqual(len(root.links), 3) self.assertEqual( root.links[0].context.trace_id, other_context1.trace_id ) self.assertEqual( root.links[0].context.span_id, other_context1.span_id ) self.assertEqual(root.links[0].attributes, None) self.assertEqual( root.links[1].context.trace_id, other_context2.trace_id ) self.assertEqual( root.links[1].context.span_id, other_context2.span_id ) self.assertEqual(root.links[1].attributes, {"name": "neighbor"}) self.assertEqual( root.links[2].context.span_id, other_context3.span_id ) self.assertEqual(root.links[2].attributes, {"component": "http"})
def add_link( self, link_target_context: "trace_api.SpanContext", attributes: types.Attributes = None, ) -> None: if attributes is None: attributes = ( Span.empty_attributes ) # TODO: empty_attributes is not a Dict. Use Mapping? self.add_lazy_link(trace_api.Link(link_target_context, attributes))
def get_exhaustive_otel_span_list() -> List[trace._Span]: trace_id = 0x6E0C63257DE34C926F9EFCD03927272E base_time = 683647322 * 10**9 # in ns start_times = ( base_time, base_time + 150 * 10**6, base_time + 300 * 10**6, base_time + 400 * 10**6, ) end_times = ( start_times[0] + (50 * 10**6), start_times[1] + (100 * 10**6), start_times[2] + (200 * 10**6), start_times[3] + (300 * 10**6), ) parent_span_context = trace_api.SpanContext(trace_id, 0x1111111111111111, is_remote=False) other_context = trace_api.SpanContext(trace_id, 0x2222222222222222, is_remote=False) span1 = trace._Span( name="test-span-1", context=trace_api.SpanContext( trace_id, 0x34BF92DEEFC58C92, is_remote=False, trace_flags=TraceFlags(TraceFlags.SAMPLED), ), parent=parent_span_context, events=(trace.Event( name="event0", timestamp=base_time + 50 * 10**6, attributes={ "annotation_bool": True, "annotation_string": "annotation_test", "key_float": 0.3, }, ), ), links=(trace_api.Link(context=other_context, attributes={"key_bool": True}), ), resource=trace.Resource({}), ) span1.start(start_time=start_times[0]) span1.set_attribute("key_bool", False) span1.set_attribute("key_string", "hello_world") span1.set_attribute("key_float", 111.22) span1.set_status(Status(StatusCode.OK)) span1.end(end_time=end_times[0]) span2 = trace._Span( name="test-span-2", context=parent_span_context, parent=None, resource=trace.Resource( attributes={"key_resource": "some_resource"}), ) span2.start(start_time=start_times[1]) span2.set_status(Status(StatusCode.ERROR, "Example description")) span2.end(end_time=end_times[1]) span3 = trace._Span( name="test-span-3", context=other_context, parent=None, resource=trace.Resource( attributes={"key_resource": "some_resource"}), ) span3.start(start_time=start_times[2]) span3.set_attribute("key_string", "hello_world") span3.end(end_time=end_times[2]) span4 = trace._Span( name="test-span-3", context=other_context, parent=None, resource=trace.Resource({}), instrumentation_info=InstrumentationInfo(name="name", version="version"), ) span4.start(start_time=start_times[3]) span4.end(end_time=end_times[3]) return [span1, span2, span3, span4]
def test_translate_to_jaeger(self): span_names = ("test1", "test2", "test3") trace_id = 0x6E0C63257DE34C926F9EFCD03927272E span_id = 0x34BF92DEEFC58C92 parent_id = 0x1111111111111111 other_id = 0x2222222222222222 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 ) parent_span_context = trace_api.SpanContext( trace_id, parent_id, is_remote=False ) other_context = trace_api.SpanContext( trace_id, other_id, is_remote=False ) event_attributes = OrderedDict( [ ("annotation_bool", True), ("annotation_string", "annotation_test"), ("key_float", 0.3), ] ) event_timestamp = base_time + 50 * 10 ** 6 # pylint:disable=protected-access event_timestamp_proto = pb_translator._proto_timestamp_from_epoch_nanos( event_timestamp ) event = trace.Event( name="event0", timestamp=event_timestamp, attributes=event_attributes, ) link_attributes = {"key_bool": True} link = trace_api.Link( context=other_context, attributes=link_attributes ) default_tags = [ model_pb2.KeyValue( key="span.kind", v_type=model_pb2.ValueType.STRING, v_str="internal", ), ] otel_spans = [ trace._Span( name=span_names[0], context=span_context, parent=parent_span_context, events=(event,), links=(link,), kind=trace_api.SpanKind.CLIENT, ), trace._Span( name=span_names[1], context=parent_span_context, parent=None ), trace._Span( name=span_names[2], context=other_context, parent=None ), ] otel_spans[0].start(start_time=start_times[0]) # added here to preserve order 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_tuple", ("tuple_element",)) otel_spans[0].resource = Resource( attributes={"key_resource": "some_resource"} ) otel_spans[0].set_status( Status(StatusCode.ERROR, "Example description") ) otel_spans[0].end(end_time=end_times[0]) otel_spans[1].start(start_time=start_times[1]) otel_spans[1].resource = Resource({}) otel_spans[1].end(end_time=end_times[1]) otel_spans[2].start(start_time=start_times[2]) otel_spans[2].resource = Resource({}) otel_spans[2].set_status(Status(StatusCode.OK, "Example description")) otel_spans[2].end(end_time=end_times[2]) otel_spans[2].instrumentation_info = InstrumentationInfo( name="name", version="version" ) translate = Translate(otel_spans) # pylint: disable=protected-access spans = translate._translate(pb_translator.ProtobufTranslator("svc")) span1_start_time = pb_translator._proto_timestamp_from_epoch_nanos( start_times[0] ) span2_start_time = pb_translator._proto_timestamp_from_epoch_nanos( start_times[1] ) span3_start_time = pb_translator._proto_timestamp_from_epoch_nanos( start_times[2] ) span1_end_time = pb_translator._proto_timestamp_from_epoch_nanos( end_times[0] ) span2_end_time = pb_translator._proto_timestamp_from_epoch_nanos( end_times[1] ) span3_end_time = pb_translator._proto_timestamp_from_epoch_nanos( end_times[2] ) span1_duration = pb_translator._duration_from_two_time_stamps( span1_start_time, span1_end_time ) span2_duration = pb_translator._duration_from_two_time_stamps( span2_start_time, span2_end_time ) span3_duration = pb_translator._duration_from_two_time_stamps( span3_start_time, span3_end_time ) expected_spans = [ model_pb2.Span( operation_name=span_names[0], trace_id=pb_translator._trace_id_to_bytes(trace_id), span_id=pb_translator._span_id_to_bytes(span_id), start_time=span1_start_time, duration=span1_duration, flags=0, tags=[ model_pb2.KeyValue( key="key_bool", v_type=model_pb2.ValueType.BOOL, v_bool=False, ), model_pb2.KeyValue( key="key_string", v_type=model_pb2.ValueType.STRING, v_str="hello_world", ), model_pb2.KeyValue( key="key_float", v_type=model_pb2.ValueType.FLOAT64, v_float64=111.22, ), model_pb2.KeyValue( key="key_tuple", v_type=model_pb2.ValueType.STRING, v_str="('tuple_element',)", ), model_pb2.KeyValue( key="key_resource", v_type=model_pb2.ValueType.STRING, v_str="some_resource", ), model_pb2.KeyValue( key="otel.status_code", v_type=model_pb2.ValueType.STRING, v_str="ERROR", ), model_pb2.KeyValue( key="otel.status_description", v_type=model_pb2.ValueType.STRING, v_str="Example description", ), model_pb2.KeyValue( key="span.kind", v_type=model_pb2.ValueType.STRING, v_str="client", ), model_pb2.KeyValue( key="error", v_type=model_pb2.ValueType.BOOL, v_bool=True, ), ], references=[ model_pb2.SpanRef( ref_type=model_pb2.SpanRefType.FOLLOWS_FROM, trace_id=pb_translator._trace_id_to_bytes(trace_id), span_id=pb_translator._span_id_to_bytes(other_id), ) ], logs=[ model_pb2.Log( timestamp=event_timestamp_proto, fields=[ model_pb2.KeyValue( key="annotation_bool", v_type=model_pb2.ValueType.BOOL, v_bool=True, ), model_pb2.KeyValue( key="annotation_string", v_type=model_pb2.ValueType.STRING, v_str="annotation_test", ), model_pb2.KeyValue( key="key_float", v_type=model_pb2.ValueType.FLOAT64, v_float64=0.3, ), model_pb2.KeyValue( key="message", v_type=model_pb2.ValueType.STRING, v_str="event0", ), ], ) ], process=model_pb2.Process( service_name="svc", tags=[ model_pb2.KeyValue( key="key_resource", v_str="some_resource", v_type=model_pb2.ValueType.STRING, ) ], ), ), model_pb2.Span( operation_name=span_names[1], trace_id=pb_translator._trace_id_to_bytes(trace_id), span_id=pb_translator._span_id_to_bytes(parent_id), start_time=span2_start_time, duration=span2_duration, flags=0, tags=default_tags, process=model_pb2.Process(service_name="svc",), ), model_pb2.Span( operation_name=span_names[2], trace_id=pb_translator._trace_id_to_bytes(trace_id), span_id=pb_translator._span_id_to_bytes(other_id), start_time=span3_start_time, duration=span3_duration, flags=0, tags=[ model_pb2.KeyValue( key="otel.status_code", v_type=model_pb2.ValueType.STRING, v_str="OK", ), model_pb2.KeyValue( key="otel.status_description", v_type=model_pb2.ValueType.STRING, v_str="Example description", ), model_pb2.KeyValue( key="span.kind", v_type=model_pb2.ValueType.STRING, v_str="internal", ), model_pb2.KeyValue( key="otel.instrumentation_library.name", v_type=model_pb2.ValueType.STRING, v_str="name", ), model_pb2.KeyValue( key="otel.instrumentation_library.version", v_type=model_pb2.ValueType.STRING, v_str="version", ), ], process=model_pb2.Process(service_name="svc",), ), ] # events are complicated to compare because order of fields # (attributes) in otel is not important but in jeager it is # pylint: disable=no-member self.assertCountEqual( spans[0].logs[0].fields, expected_spans[0].logs[0].fields, ) self.assertEqual(spans, expected_spans)
def test_translate_to_jaeger(self): # pylint: disable=invalid-name self.maxDiff = None span_names = ("test1", "test2", "test3") trace_id = 0x6E0C63257DE34C926F9EFCD03927272E trace_id_high = 0x6E0C63257DE34C92 trace_id_low = 0x6F9EFCD03927272E span_id = 0x34BF92DEEFC58C92 parent_id = 0x1111111111111111 other_id = 0x2222222222222222 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 ) parent_span_context = trace_api.SpanContext( trace_id, parent_id, is_remote=False ) other_context = trace_api.SpanContext( trace_id, other_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 = trace_api.Link( context=other_context, attributes=link_attributes ) default_tags = [ jaeger.Tag( key="span.kind", vType=jaeger.TagType.STRING, vStr="internal", ), ] otel_spans = [ trace._Span( name=span_names[0], context=span_context, parent=parent_span_context, events=(event,), links=(link,), kind=trace_api.SpanKind.CLIENT, resource=Resource( attributes={"key_resource": "some_resource"} ), ), trace._Span( name=span_names[1], context=parent_span_context, parent=None, resource=Resource({}), ), trace._Span( name=span_names[2], context=other_context, parent=None, resource=Resource({}), instrumentation_info=InstrumentationInfo( name="name", version="version" ), ), ] otel_spans[0].start(start_time=start_times[0]) # added here to preserve order 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_tuple", ("tuple_element",)) otel_spans[0].set_status( Status(StatusCode.ERROR, "Example description") ) otel_spans[0].end(end_time=end_times[0]) otel_spans[1].start(start_time=start_times[1]) otel_spans[1].end(end_time=end_times[1]) otel_spans[2].start(start_time=start_times[2]) otel_spans[2].set_status(Status(StatusCode.OK, "Example description")) otel_spans[2].end(end_time=end_times[2]) translate = Translate(otel_spans) # pylint: disable=protected-access spans = translate._translate(ThriftTranslator()) expected_spans = [ jaeger.Span( operationName=span_names[0], traceIdHigh=trace_id_high, traceIdLow=trace_id_low, spanId=span_id, parentSpanId=parent_id, startTime=start_times[0] // 10 ** 3, duration=durations[0] // 10 ** 3, flags=0, tags=[ jaeger.Tag( key="key_bool", vType=jaeger.TagType.BOOL, vBool=False ), jaeger.Tag( key="key_string", vType=jaeger.TagType.STRING, vStr="hello_world", ), jaeger.Tag( key="key_float", vType=jaeger.TagType.DOUBLE, vDouble=111.22, ), jaeger.Tag( key="key_tuple", vType=jaeger.TagType.STRING, vStr="('tuple_element',)", ), jaeger.Tag( key="key_resource", vType=jaeger.TagType.STRING, vStr="some_resource", ), jaeger.Tag( key="otel.status_code", vType=jaeger.TagType.STRING, vStr="ERROR", ), jaeger.Tag( key="otel.status_description", vType=jaeger.TagType.STRING, vStr="Example description", ), jaeger.Tag( key="span.kind", vType=jaeger.TagType.STRING, vStr="client", ), jaeger.Tag( key="error", vType=jaeger.TagType.BOOL, vBool=True ), ], references=[ jaeger.SpanRef( refType=jaeger.SpanRefType.FOLLOWS_FROM, traceIdHigh=trace_id_high, traceIdLow=trace_id_low, spanId=other_id, ) ], logs=[ jaeger.Log( timestamp=event_timestamp // 10 ** 3, fields=[ jaeger.Tag( key="annotation_bool", vType=jaeger.TagType.BOOL, vBool=True, ), jaeger.Tag( key="annotation_string", vType=jaeger.TagType.STRING, vStr="annotation_test", ), jaeger.Tag( key="key_float", vType=jaeger.TagType.DOUBLE, vDouble=0.3, ), jaeger.Tag( key="message", vType=jaeger.TagType.STRING, vStr="event0", ), ], ) ], ), jaeger.Span( operationName=span_names[1], traceIdHigh=trace_id_high, traceIdLow=trace_id_low, spanId=parent_id, parentSpanId=0, startTime=start_times[1] // 10 ** 3, duration=durations[1] // 10 ** 3, flags=0, tags=default_tags, ), jaeger.Span( operationName=span_names[2], traceIdHigh=trace_id_high, traceIdLow=trace_id_low, spanId=other_id, parentSpanId=0, startTime=start_times[2] // 10 ** 3, duration=durations[2] // 10 ** 3, flags=0, tags=[ jaeger.Tag( key="otel.status_code", vType=jaeger.TagType.STRING, vStr="OK", ), jaeger.Tag( key="otel.status_description", vType=jaeger.TagType.STRING, vStr="Example description", ), jaeger.Tag( key="span.kind", vType=jaeger.TagType.STRING, vStr="internal", ), jaeger.Tag( key=jaeger_exporter.translate.NAME_KEY, vType=jaeger.TagType.STRING, vStr="name", ), jaeger.Tag( key=jaeger_exporter.translate.VERSION_KEY, vType=jaeger.TagType.STRING, vStr="version", ), ], ), ] # events are complicated to compare because order of fields # (attributes) in otel is not important but in jeager it is self.assertCountEqual( spans[0].logs[0].fields, expected_spans[0].logs[0].fields ) # get rid of fields to be able to compare the whole spans spans[0].logs[0].fields = None expected_spans[0].logs[0].fields = None self.assertEqual(spans, expected_spans)
def start_span( self, operation_name=None, child_of=None, references=None, tags=None, start_time=None, ignore_active_span=False, ): """Implements the ``start_span()`` method from the base class. Starts a span. In terms of functionality, this method behaves exactly like the same method on a "regular" OpenTracing tracer. See :meth:`opentracing.Tracer.start_span` for more details. Args: operation_name(:obj:`str`): Name of the operation represented by the new span from the perspective of the current service. child_of(:class:`SpanShim` or :class:`SpanContextShim`, optional): A :class:`SpanShim` or :class:`SpanContextShim` representing the parent in a "child of" reference. If specified, the *references* parameter must be omitted. Defaults to `None`. references(:obj:`list`, optional): A list of :class:`opentracing.Reference` objects that identify one or more parents of type :class:`SpanContextShim`. Defaults to `None`. tags(:obj:`dict`, optional): A dictionary of tags. The keys must be of type :obj:`str`. The values may be one of :obj:`str`, :obj:`bool`, :obj:`int`, :obj:`float`. Defaults to `None`. start_time(:obj:`float`, optional): An explicit start time expressed as the number of seconds since the epoch as returned by :func:`time.time()`. Defaults to `None`. ignore_active_span(:obj:`bool`, optional): Ignore the currently-active span in the OpenTelemetry tracer and make the created span the root span of a new trace. Defaults to `False`. Returns: An already-started :class:`SpanShim` instance. """ # Use active span as parent when no explicit parent is specified. if not ignore_active_span and not child_of: child_of = self.active_span # Use the specified parent or the active span if possible. Otherwise, # use a `None` parent, which triggers the creation of a new trace. parent = child_of.unwrap() if child_of else None links = [] if references: for ref in references: links.append(trace_api.Link(ref.referenced_context.unwrap())) # The OpenTracing API expects time values to be `float` values which # represent the number of seconds since the epoch. OpenTelemetry # represents time values as nanoseconds since the epoch. start_time_ns = start_time if start_time_ns is not None: start_time_ns = util.time_seconds_to_ns(start_time) span = self._otel_tracer.start_span( operation_name, parent, links=links, attributes=tags, start_time=start_time_ns, ) context = SpanContextShim(span.get_context()) return SpanShim(self, context, span)
# jaeger_exporter = jaeger.JaegerSpanExporter( # service_name="my-helloworld-service", # collector_endpoint="localhost:14250", # insecure=True, # transport_format="protobuf", # ) # create a BatchSpanProcessor and add the exporter to it span_processor = BatchSpanProcessor(jaeger_exporter) # add to the tracer factory trace.get_tracer_provider().add_span_processor(span_processor) # create some spans for testing with tracer.start_as_current_span("foo") as foo: time.sleep(0.1) foo.set_attribute("my_atribbute", True) foo.add_event("event in foo", {"name": "foo1"}) with tracer.start_as_current_span( "bar", links=[trace.Link(foo.get_span_context())]) as bar: time.sleep(0.2) bar.set_attribute("speed", 100.0) with tracer.start_as_current_span("baz") as baz: time.sleep(0.3) baz.set_attribute("name", "mauricio") time.sleep(0.2) time.sleep(0.1)
def test_export_protobuf(self): span_names = ("test1", "test2", "test3", "test4") trace_id = 0x6E0C63257DE34C926F9EFCD03927272E span_id = 0x34BF92DEEFC58C92 parent_id = 0x1111111111111111 other_id = 0x2222222222222222 base_time = 683647322 * 10**9 # in ns start_times = ( base_time, base_time + 150 * 10**6, base_time + 300 * 10**6, base_time + 400 * 10**6, ) durations = (50 * 10**6, 100 * 10**6, 200 * 10**6, 300 * 10**6) end_times = ( start_times[0] + durations[0], start_times[1] + durations[1], start_times[2] + durations[2], start_times[3] + durations[3], ) span_context = trace_api.SpanContext( trace_id, span_id, is_remote=False, trace_flags=TraceFlags(TraceFlags.SAMPLED), ) parent_span_context = trace_api.SpanContext(trace_id, parent_id, is_remote=False) other_context = trace_api.SpanContext(trace_id, other_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 = trace_api.Link(context=other_context, attributes=link_attributes) otel_spans = [ trace._Span( name=span_names[0], context=span_context, parent=parent_span_context, resource=Resource({}), events=(event, ), links=(link, ), ), trace._Span( name=span_names[1], context=parent_span_context, parent=None, resource=Resource( attributes={"key_resource": "some_resource"}), ), trace._Span( name=span_names[2], context=other_context, parent=None, resource=Resource( attributes={"key_resource": "some_resource"}), ), trace._Span( name=span_names[3], context=other_context, parent=None, resource=Resource({}), instrumentation_info=InstrumentationInfo(name="name", version="version"), ), ] otel_spans[0].start(start_time=start_times[0]) # added here to preserve order 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_status( Status(StatusCode.ERROR, "Example description")) otel_spans[0].end(end_time=end_times[0]) otel_spans[1].start(start_time=start_times[1]) otel_spans[1].set_status(Status(StatusCode.OK)) otel_spans[1].end(end_time=end_times[1]) otel_spans[2].start(start_time=start_times[2]) otel_spans[2].set_attribute("key_string", "hello_world") otel_spans[2].end(end_time=end_times[2]) otel_spans[3].start(start_time=start_times[3]) otel_spans[3].end(end_time=end_times[3]) service_name = "test-service" local_endpoint = zipkin_pb2.Endpoint(service_name=service_name, port=9411) span_kind = SPAN_KIND_MAP_PROTOBUF[SpanKind.INTERNAL] expected_spans = zipkin_pb2.ListOfSpans(spans=[ zipkin_pb2.Span( trace_id=trace_id.to_bytes(length=16, byteorder="big", signed=False), id=ZipkinSpanExporter.format_pbuf_span_id(span_id), name=span_names[0], timestamp=nsec_to_usec_round(start_times[0]), duration=nsec_to_usec_round(durations[0]), local_endpoint=local_endpoint, kind=span_kind, tags={ "key_bool": "false", "key_string": "hello_world", "key_float": "111.22", "otel.status_code": "ERROR", "error": "Example description", }, debug=True, parent_id=ZipkinSpanExporter.format_pbuf_span_id(parent_id), annotations=[ zipkin_pb2.Annotation( timestamp=nsec_to_usec_round(event_timestamp), value=json.dumps({ "event0": { "annotation_bool": True, "annotation_string": "annotation_test", "key_float": 0.3, } }), ), ], ), zipkin_pb2.Span( trace_id=trace_id.to_bytes(length=16, byteorder="big", signed=False), id=ZipkinSpanExporter.format_pbuf_span_id(parent_id), name=span_names[1], timestamp=nsec_to_usec_round(start_times[1]), duration=nsec_to_usec_round(durations[1]), local_endpoint=local_endpoint, kind=span_kind, tags={ "key_resource": "some_resource", "otel.status_code": "OK", }, ), zipkin_pb2.Span( trace_id=trace_id.to_bytes(length=16, byteorder="big", signed=False), id=ZipkinSpanExporter.format_pbuf_span_id(other_id), name=span_names[2], timestamp=nsec_to_usec_round(start_times[2]), duration=nsec_to_usec_round(durations[2]), local_endpoint=local_endpoint, kind=span_kind, tags={ "key_string": "hello_world", "key_resource": "some_resource", }, ), zipkin_pb2.Span( trace_id=trace_id.to_bytes(length=16, byteorder="big", signed=False), id=ZipkinSpanExporter.format_pbuf_span_id(other_id), name=span_names[3], timestamp=nsec_to_usec_round(start_times[3]), duration=nsec_to_usec_round(durations[3]), local_endpoint=local_endpoint, kind=span_kind, tags={ NAME_KEY: "name", VERSION_KEY: "version" }, ), ], ) exporter = ZipkinSpanExporter( service_name, transport_format=TRANSPORT_FORMAT_PROTOBUF) mock_post = MagicMock() with patch("requests.post", mock_post): mock_post.return_value = MockResponse(200) status = exporter.export(otel_spans) self.assertEqual(SpanExportResult.SUCCESS, status) # pylint: disable=unsubscriptable-object kwargs = mock_post.call_args[1] self.assertEqual(kwargs["url"], "http://localhost:9411/api/v2/spans") self.assertEqual(kwargs["headers"]["Content-Type"], "application/x-protobuf") self.assertEqual(zipkin_pb2.ListOfSpans.FromString(kwargs["data"]), expected_spans)
def test_export(self): span_names = ("test1", "test2", "test3") trace_id = 0x6E0C63257DE34C926F9EFCD03927272E span_id = 0x34BF92DEEFC58C92 parent_id = 0x1111111111111111 other_id = 0x2222222222222222 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, trace_options=TraceOptions(TraceOptions.SAMPLED), ) parent_context = trace_api.SpanContext(trace_id, parent_id) other_context = trace_api.SpanContext(trace_id, other_id) event_attributes = { "annotation_bool": True, "annotation_string": "annotation_test", "key_float": 0.3, } event_timestamp = base_time + 50 * 10**6 event = trace_api.Event( name="event0", timestamp=event_timestamp, attributes=event_attributes, ) link_attributes = {"key_bool": True} link = trace_api.Link(context=other_context, attributes=link_attributes) otel_spans = [ trace.Span( name=span_names[0], context=span_context, parent=parent_context, events=(event, ), links=(link, ), ), trace.Span(name=span_names[1], context=parent_context, parent=None), trace.Span(name=span_names[2], context=other_context, parent=None), ] otel_spans[0].start_time = start_times[0] # added here to preserve order 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].end_time = end_times[0] otel_spans[1].start_time = start_times[1] otel_spans[1].end_time = end_times[1] otel_spans[2].start_time = start_times[2] otel_spans[2].end_time = end_times[2] service_name = "test-service" local_endpoint = { "serviceName": service_name, "port": 9411, } exporter = ZipkinSpanExporter(service_name) expected = [ { "traceId": format(trace_id, "x"), "id": format(span_id, "x"), "name": span_names[0], "timestamp": start_times[0] // 10**3, "duration": durations[0] // 10**3, "localEndpoint": local_endpoint, "kind": None, "tags": { "key_bool": "False", "key_string": "hello_world", "key_float": "111.22", }, "annotations": [{ "timestamp": event_timestamp // 10**3, "value": "event0", }], "debug": 1, "parentId": format(parent_id, "x"), }, { "traceId": format(trace_id, "x"), "id": format(parent_id, "x"), "name": span_names[1], "timestamp": start_times[1] // 10**3, "duration": durations[1] // 10**3, "localEndpoint": local_endpoint, "kind": None, "tags": None, "annotations": None, }, { "traceId": format(trace_id, "x"), "id": format(other_id, "x"), "name": span_names[2], "timestamp": start_times[2] // 10**3, "duration": durations[2] // 10**3, "localEndpoint": local_endpoint, "kind": None, "tags": None, "annotations": None, }, ] mock_post = MagicMock() with patch("requests.post", mock_post): mock_post.return_value = MockResponse(200) status = exporter.export(otel_spans) self.assertEqual(SpanExportResult.SUCCESS, status) mock_post.assert_called_with( url="http://localhost:9411/api/v2/spans", data=json.dumps(expected), headers={"Content-Type": "application/json"}, )
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, )
def test_translate_to_jaeger(self): # pylint: disable=invalid-name self.maxDiff = None span_names = ("test1", "test2", "test3") trace_id = 0x6E0C63257DE34C926F9EFCD03927272E trace_id_high = 0x6E0C63257DE34C92 trace_id_low = 0x6F9EFCD03927272E span_id = 0x34BF92DEEFC58C92 parent_id = 0x1111111111111111 other_id = 0x2222222222222222 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) parent_context = trace_api.SpanContext(trace_id, parent_id) other_context = trace_api.SpanContext(trace_id, other_id) event_attributes = { "annotation_bool": True, "annotation_string": "annotation_test", "key_float": 0.3, } event_timestamp = base_time + 50 * 10**6 event = trace_api.Event( name="event0", timestamp=event_timestamp, attributes=event_attributes, ) link_attributes = {"key_bool": True} link = trace_api.Link(context=other_context, attributes=link_attributes) otel_spans = [ trace.Span( name=span_names[0], context=span_context, parent=parent_context, events=(event, ), links=(link, ), ), trace.Span(name=span_names[1], context=parent_context, parent=None), trace.Span(name=span_names[2], context=other_context, parent=None), ] otel_spans[0].start_time = start_times[0] # added here to preserve order 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].end_time = end_times[0] otel_spans[1].start_time = start_times[1] otel_spans[1].end_time = end_times[1] otel_spans[2].start_time = start_times[2] otel_spans[2].end_time = end_times[2] # pylint: disable=protected-access spans = jaeger_exporter._translate_to_jaeger(otel_spans) expected_spans = [ jaeger.Span( operationName=span_names[0], traceIdHigh=trace_id_high, traceIdLow=trace_id_low, spanId=span_id, parentSpanId=parent_id, startTime=start_times[0] // 10**3, duration=durations[0] // 10**3, flags=0, tags=[ jaeger.Tag(key="key_bool", vType=jaeger.TagType.BOOL, vBool=False), jaeger.Tag( key="key_string", vType=jaeger.TagType.STRING, vStr="hello_world", ), jaeger.Tag( key="key_float", vType=jaeger.TagType.DOUBLE, vDouble=111.22, ), ], references=[ jaeger.SpanRef( refType=jaeger.SpanRefType.FOLLOWS_FROM, traceIdHigh=trace_id_high, traceIdLow=trace_id_low, spanId=other_id, ) ], logs=[ jaeger.Log( timestamp=event_timestamp // 10**3, fields=[ jaeger.Tag( key="annotation_bool", vType=jaeger.TagType.BOOL, vBool=True, ), jaeger.Tag( key="annotation_string", vType=jaeger.TagType.STRING, vStr="annotation_test", ), jaeger.Tag( key="key_float", vType=jaeger.TagType.DOUBLE, vDouble=0.3, ), jaeger.Tag( key="message", vType=jaeger.TagType.STRING, vStr="event0", ), ], ) ], ), jaeger.Span( operationName=span_names[1], traceIdHigh=trace_id_high, traceIdLow=trace_id_low, spanId=parent_id, parentSpanId=0, startTime=start_times[1] // 10**3, duration=durations[1] // 10**3, flags=0, ), jaeger.Span( operationName=span_names[2], traceIdHigh=trace_id_high, traceIdLow=trace_id_low, spanId=other_id, parentSpanId=0, startTime=start_times[2] // 10**3, duration=durations[2] // 10**3, flags=0, ), ] # events are complicated to compare because order of fields # (attributes) in otel is not important but in jeager it is self.assertCountEqual(spans[0].logs[0].fields, expected_spans[0].logs[0].fields) # get rid of fields to be able to compare the whole spans spans[0].logs[0].fields = None expected_spans[0].logs[0].fields = None self.assertEqual(spans, expected_spans)
# collector_port=14268, # collector_endpoint="/api/traces?format=jaeger.thrift", # username=xxxx, # optional # password=xxxx, # optional ) # create a BatchExportSpanProcessor and add the exporter to it span_processor = BatchExportSpanProcessor(jaeger_exporter) # add to the tracer factory trace.tracer_provider().add_span_processor(span_processor) # create some spans for testing with tracer.start_as_current_span("foo") as foo: time.sleep(0.1) foo.set_attribute("my_atribbute", True) foo.add_event("event in foo", {"name": "foo1"}) with tracer.start_as_current_span("bar", links=[trace.Link(foo.get_context()) ]) as bar: time.sleep(0.2) bar.set_attribute("speed", 100.0) with tracer.start_as_current_span("baz") as baz: time.sleep(0.3) baz.set_attribute("name", "mauricio") time.sleep(0.2) time.sleep(0.1)
def test_export_json(self): span_names = ("test1", "test2", "test3", "test4") trace_id = 0x6E0C63257DE34C926F9EFCD03927272E span_id = 0x34BF92DEEFC58C92 parent_id = 0x1111111111111111 other_id = 0x2222222222222222 base_time = 683647322 * 10**9 # in ns start_times = ( base_time, base_time + 150 * 10**6, base_time + 300 * 10**6, base_time + 400 * 10**6, ) durations = (50 * 10**6, 100 * 10**6, 200 * 10**6, 300 * 10**6) end_times = ( start_times[0] + durations[0], start_times[1] + durations[1], start_times[2] + durations[2], start_times[3] + durations[3], ) span_context = trace_api.SpanContext( trace_id, span_id, is_remote=False, trace_flags=TraceFlags(TraceFlags.SAMPLED), ) parent_span_context = trace_api.SpanContext(trace_id, parent_id, is_remote=False) other_context = trace_api.SpanContext(trace_id, other_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 = trace_api.Link(context=other_context, attributes=link_attributes) otel_spans = [ trace._Span( name=span_names[0], context=span_context, parent=parent_span_context, events=(event, ), links=(link, ), resource=Resource({}), ), trace._Span( name=span_names[1], context=parent_span_context, parent=None, resource=Resource( attributes={"key_resource": "some_resource"}), ), trace._Span( name=span_names[2], context=other_context, parent=None, resource=Resource( attributes={"key_resource": "some_resource"}), ), trace._Span( name=span_names[3], context=other_context, parent=None, resource=Resource({}), instrumentation_info=InstrumentationInfo(name="name", version="version"), ), ] otel_spans[0].start(start_time=start_times[0]) # added here to preserve order 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_status( Status(StatusCode.ERROR, "Example description")) otel_spans[0].end(end_time=end_times[0]) otel_spans[1].start(start_time=start_times[1]) otel_spans[1].end(end_time=end_times[1]) otel_spans[2].start(start_time=start_times[2]) otel_spans[2].set_attribute("key_string", "hello_world") otel_spans[2].end(end_time=end_times[2]) otel_spans[3].start(start_time=start_times[3]) otel_spans[3].end(end_time=end_times[3]) service_name = "test-service" local_endpoint = {"serviceName": service_name, "port": 9411} span_kind = SPAN_KIND_MAP_JSON[SpanKind.INTERNAL] exporter = ZipkinSpanExporter(service_name) expected_spans = [ { "traceId": format(trace_id, "x"), "id": format(span_id, "x"), "name": span_names[0], "timestamp": start_times[0] // 10**3, "duration": durations[0] // 10**3, "localEndpoint": local_endpoint, "kind": span_kind, "tags": { "key_bool": "false", "key_string": "hello_world", "key_float": "111.22", "otel.status_code": "ERROR", "error": "Example description", }, "debug": True, "parentId": format(parent_id, "x"), "annotations": [{ "timestamp": event_timestamp // 10**3, "value": { "event0": { "annotation_bool": True, "annotation_string": "annotation_test", "key_float": 0.3, } }, }], }, { "traceId": format(trace_id, "x"), "id": format(parent_id, "x"), "name": span_names[1], "timestamp": start_times[1] // 10**3, "duration": durations[1] // 10**3, "localEndpoint": local_endpoint, "kind": span_kind, "tags": { "key_resource": "some_resource" }, "annotations": None, }, { "traceId": format(trace_id, "x"), "id": format(other_id, "x"), "name": span_names[2], "timestamp": start_times[2] // 10**3, "duration": durations[2] // 10**3, "localEndpoint": local_endpoint, "kind": span_kind, "tags": { "key_string": "hello_world", "key_resource": "some_resource", }, "annotations": None, }, { "traceId": format(trace_id, "x"), "id": format(other_id, "x"), "name": span_names[3], "timestamp": start_times[3] // 10**3, "duration": durations[3] // 10**3, "localEndpoint": local_endpoint, "kind": span_kind, "tags": { NAME_KEY: "name", VERSION_KEY: "version" }, "annotations": None, }, ] mock_post = MagicMock() with patch("requests.post", mock_post): mock_post.return_value = MockResponse(200) status = exporter.export(otel_spans) self.assertEqual(SpanExportResult.SUCCESS, status) # pylint: disable=unsubscriptable-object kwargs = mock_post.call_args[1] self.assertEqual(kwargs["url"], "http://localhost:9411/api/v2/spans") self.assertEqual(kwargs["headers"]["Content-Type"], "application/json") actual_spans = sorted(json.loads(kwargs["data"]), key=lambda span: span["timestamp"]) for expected, actual in zip(expected_spans, actual_spans): expected_annotations = expected.pop("annotations", None) actual_annotations = actual.pop("annotations", None) if actual_annotations: for annotation in actual_annotations: annotation["value"] = json.loads(annotation["value"]) self.assertEqual(expected, actual) self.assertEqual(expected_annotations, actual_annotations)
def test_span_members(self): tracer = trace.Tracer("test_span_members") other_context1 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), ) other_context2 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), ) other_context3 = trace_api.SpanContext( trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), ) self.assertIsNone(tracer.get_current_span()) with tracer.start_span("root") as root: # attributes root.set_attribute("component", "http") root.set_attribute("http.method", "GET") root.set_attribute("http.url", "https://example.com:779/path/12/?q=d#123") root.set_attribute("http.status_code", 200) root.set_attribute("http.status_text", "OK") root.set_attribute("misc.pi", 3.14) # Setting an attribute with the same key as an existing attribute # SHOULD overwrite the existing attribute's value. root.set_attribute("attr-key", "attr-value1") root.set_attribute("attr-key", "attr-value2") self.assertEqual(len(root.attributes), 7) self.assertEqual(root.attributes["component"], "http") self.assertEqual(root.attributes["http.method"], "GET") self.assertEqual( root.attributes["http.url"], "https://example.com:779/path/12/?q=d#123", ) self.assertEqual(root.attributes["http.status_code"], 200) self.assertEqual(root.attributes["http.status_text"], "OK") self.assertEqual(root.attributes["misc.pi"], 3.14) self.assertEqual(root.attributes["attr-key"], "attr-value2") # events root.add_event("event0") root.add_event("event1", {"name": "birthday"}) now = util.time_ns() root.add_lazy_event( trace_api.Event("event2", now, {"name": "hello"})) self.assertEqual(len(root.events), 3) self.assertEqual(root.events[0].name, "event0") self.assertEqual(root.events[0].attributes, {}) self.assertEqual(root.events[1].name, "event1") self.assertEqual(root.events[1].attributes, {"name": "birthday"}) self.assertEqual(root.events[2].name, "event2") self.assertEqual(root.events[2].attributes, {"name": "hello"}) self.assertEqual(root.events[2].timestamp, now) # links root.add_link(other_context1) root.add_link(other_context2, {"name": "neighbor"}) root.add_lazy_link( trace_api.Link(other_context3, {"component": "http"})) self.assertEqual(len(root.links), 3) self.assertEqual(root.links[0].context.trace_id, other_context1.trace_id) self.assertEqual(root.links[0].context.span_id, other_context1.span_id) self.assertEqual(root.links[0].attributes, {}) self.assertEqual(root.links[1].context.trace_id, other_context2.trace_id) self.assertEqual(root.links[1].context.span_id, other_context2.span_id) self.assertEqual(root.links[1].attributes, {"name": "neighbor"}) self.assertEqual(root.links[2].context.span_id, other_context3.span_id) self.assertEqual(root.links[2].attributes, {"component": "http"}) # name root.update_name("toor") self.assertEqual(root.name, "toor")