def test_events(self): self.assertIsNone(self.tracer.get_current_span()) with self.tracer.start_as_current_span("root") as root: # only event name root.add_event("event0") # event name and attributes now = time_ns() root.add_event("event1", {"name": "pluto"}) # event name, attributes and timestamp now = time_ns() root.add_event("event2", {"name": "birthday"}, now) # lazy event root.add_lazy_event( trace_api.Event("event3", {"name": "hello"}, now)) self.assertEqual(len(root.events), 4) 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": "pluto"}) self.assertEqual(root.events[2].name, "event2") self.assertEqual(root.events[2].attributes, {"name": "birthday"}) self.assertEqual(root.events[2].timestamp, now) self.assertEqual(root.events[3].name, "event3") self.assertEqual(root.events[3].attributes, {"name": "hello"}) self.assertEqual(root.events[3].timestamp, now)
def add_event( self, name: str, timestamp: int = None, attributes: types.Attributes = None, ) -> None: self.add_lazy_event( trace_api.Event( name, time_ns() if timestamp is None else timestamp, Span.empty_attributes if attributes is None else attributes, ))
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 add_event( self, name: str, attributes: types.Attributes = None ) -> None: if attributes is None: attributes = Span.empty_attributes self.add_lazy_event(trace_api.Event(name, util.time_ns(), attributes))
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_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_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) default_tags = [ jaeger.Tag( key="status.code", vType=jaeger.TagType.LONG, vLong=StatusCanonicalCode.OK.value, ), jaeger.Tag(key="status.message", vType=jaeger.TagType.STRING, vStr=None), jaeger.Tag( key="span.kind", vType=jaeger.TagType.STRING, vStr=trace_api.SpanKind.INTERNAL.name, ), ] otel_spans = [ trace.Span( name=span_names[0], context=span_context, parent=parent_context, events=(event, ), links=(link, ), kind=trace_api.SpanKind.CLIENT, ), 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(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(StatusCanonicalCode.UNKNOWN, "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].end(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, ), jaeger.Tag( key="status.code", vType=jaeger.TagType.LONG, vLong=StatusCanonicalCode.UNKNOWN.value, ), jaeger.Tag( key="status.message", vType=jaeger.TagType.STRING, vStr="Example description", ), jaeger.Tag( key="span.kind", vType=jaeger.TagType.STRING, vStr=trace_api.SpanKind.CLIENT.name, ), 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=default_tags, ), ] # 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 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, trace_flags=TraceFlags(TraceFlags.SAMPLED), trace_state=trace_api.TraceState({"testKey": "testValue"}), ) parent_context = trace_api.SpanContext(trace_id, parent_id) other_context = trace_api.SpanContext(trace_id, span_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_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 ) 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].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[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_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")