diff --git a/ext/opentelemetry-ext-jaeger/CHANGELOG.md b/ext/opentelemetry-ext-jaeger/CHANGELOG.md index 05ffbffe0f..90745ada0d 100644 --- a/ext/opentelemetry-ext-jaeger/CHANGELOG.md +++ b/ext/opentelemetry-ext-jaeger/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Export span status ([#367](https://github.com/open-telemetry/opentelemetry-python/pull/367)) + ## 0.3a0 Released 2019-12-11 diff --git a/ext/opentelemetry-ext-jaeger/src/opentelemetry/ext/jaeger/__init__.py b/ext/opentelemetry-ext-jaeger/src/opentelemetry/ext/jaeger/__init__.py index e9d5c5884d..e990b7d97e 100644 --- a/ext/opentelemetry-ext-jaeger/src/opentelemetry/ext/jaeger/__init__.py +++ b/ext/opentelemetry-ext-jaeger/src/opentelemetry/ext/jaeger/__init__.py @@ -26,6 +26,7 @@ from opentelemetry.ext.jaeger.gen.agent import Agent as agent from opentelemetry.ext.jaeger.gen.jaeger import Collector as jaeger from opentelemetry.sdk.trace.export import Span, SpanExporter, SpanExportResult +from opentelemetry.trace.status import StatusCanonicalCode DEFAULT_AGENT_HOST_NAME = "localhost" DEFAULT_AGENT_PORT = 6831 @@ -145,6 +146,8 @@ def _translate_to_jaeger(spans: Span): start_time_us = _nsec_to_usec_round(span.start_time) duration_us = _nsec_to_usec_round(span.end_time - span.start_time) + status = span.status + parent_id = 0 if isinstance(span.parent, trace_api.Span): parent_id = span.parent.get_context().span_id @@ -153,8 +156,16 @@ def _translate_to_jaeger(spans: Span): tags = _extract_tags(span.attributes) - # TODO: status is missing: - # https://github.com/open-telemetry/opentelemetry-python/issues/98 + tags.extend( + [ + _get_long_tag("status.code", status.canonical_code.value), + _get_string_tag("status.message", status.description), + ] + ) + + # Ensure that if Status.Code is not OK, that we set the "error" tag on the Jaeger span. + if status.canonical_code is not StatusCanonicalCode.OK: + tags.append(_get_bool_tag("error", True)) refs = _extract_refs_from_span(span) logs = _extract_logs_from_span(span) @@ -222,9 +233,7 @@ def _extract_logs_from_span(span): logs = [] for event in span.events: - fields = [] - if event.attributes is not None: - fields = _extract_tags(event.attributes) + fields = _extract_tags(event.attributes) fields.append( jaeger.Tag( @@ -241,7 +250,7 @@ def _extract_logs_from_span(span): def _extract_tags(attr): if not attr: - return None + return [] tags = [] for attribute_key, attribute_value in attr.items(): tag = _convert_attribute_to_tag(attribute_key, attribute_value) @@ -265,6 +274,18 @@ def _convert_attribute_to_tag(key, attr): return None +def _get_long_tag(key, val): + return jaeger.Tag(key=key, vLong=val, vType=jaeger.TagType.LONG) + + +def _get_string_tag(key, val): + return jaeger.Tag(key=key, vStr=val, vType=jaeger.TagType.STRING) + + +def _get_bool_tag(key, val): + return jaeger.Tag(key=key, vBool=val, vType=jaeger.TagType.BOOL) + + class AgentClientUDP: """Implement a UDP client to agent. diff --git a/ext/opentelemetry-ext-jaeger/tests/test_jaeger_exporter.py b/ext/opentelemetry-ext-jaeger/tests/test_jaeger_exporter.py index f8ead96ef0..e891393b42 100644 --- a/ext/opentelemetry-ext-jaeger/tests/test_jaeger_exporter.py +++ b/ext/opentelemetry-ext-jaeger/tests/test_jaeger_exporter.py @@ -22,6 +22,7 @@ from opentelemetry import trace as trace_api from opentelemetry.ext.jaeger.gen.jaeger import ttypes as jaeger from opentelemetry.sdk import trace +from opentelemetry.trace.status import Status, StatusCanonicalCode class TestJaegerSpanExporter(unittest.TestCase): @@ -155,6 +156,17 @@ def test_translate_to_jaeger(self): context=other_context, attributes=link_attributes ) + default_status_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, + ), + ] + otel_spans = [ trace.Span( name=span_names[0], @@ -174,6 +186,9 @@ def test_translate_to_jaeger(self): 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]) @@ -209,6 +224,19 @@ def test_translate_to_jaeger(self): 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="error", vType=jaeger.TagType.BOOL, vBool=True, + ), ], references=[ jaeger.SpanRef( @@ -255,6 +283,7 @@ def test_translate_to_jaeger(self): startTime=start_times[1] // 10 ** 3, duration=durations[1] // 10 ** 3, flags=0, + tags=default_status_tags, ), jaeger.Span( operationName=span_names[2], @@ -265,6 +294,7 @@ def test_translate_to_jaeger(self): startTime=start_times[2] // 10 ** 3, duration=durations[2] // 10 ** 3, flags=0, + tags=default_status_tags, ), ]