Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
INVALID_SPAN_CONTEXT,
Link,
NonRecordingSpan,
SpanKind,
TracerProvider,
get_current_span,
set_span_in_context,
Expand Down Expand Up @@ -667,6 +668,16 @@ def start_span(

parent_span_context = set_span_in_context(parent)

# Extract span.kind from OpenTracing tags and map to OTel SpanKind.
# The span.kind tag is removed from tags as it is not a regular
# attribute but controls the span's kind in OpenTelemetry.
kind = SpanKind.INTERNAL
if tags is not None and "span.kind" in tags:
mapped_kind = util.opentracing_kind_to_otel_kind(tags["span.kind"])
if mapped_kind is not None:
kind = mapped_kind
del tags["span.kind"]

# 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.
Expand All @@ -677,6 +688,7 @@ def start_span(
span = self._otel_tracer.start_span(
operation_name,
context=parent_span_context,
kind=kind,
links=valid_links,
attributes=tags,
start_time=start_time_ns,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from opentelemetry.trace import SpanKind

# A default event name to be used for logging events when a better event name
# can't be derived from the event's key-value pairs.
DEFAULT_EVENT_NAME = "log"
Expand Down Expand Up @@ -52,3 +54,21 @@ def event_name_from_kv(key_values):
return DEFAULT_EVENT_NAME

return key_values["event"]


_OPENTRACING_TO_OTEL_KIND = {
"client": SpanKind.CLIENT,
"server": SpanKind.SERVER,
"producer": SpanKind.PRODUCER,
"consumer": SpanKind.CONSUMER,
"internal": SpanKind.INTERNAL,
}


def opentracing_kind_to_otel_kind(opentracing_kind):
"""Maps an OpenTracing span.kind tag value to the corresponding
OpenTelemetry SpanKind.

Returns None if the kind is not recognized.
"""
return _OPENTRACING_TO_OTEL_KIND.get(opentracing_kind)
29 changes: 29 additions & 0 deletions shim/opentelemetry-opentracing-shim/tests/test_shim.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
MockTextMapPropagator,
NOOPTextMapPropagator,
)
from opentelemetry.trace import SpanKind


class TestShim(TestCase):
Expand Down Expand Up @@ -643,6 +644,34 @@ def test_active(self):
# Verify no span is active.
self.assertIsNone(self.shim.active_span)

def test_span_kind_from_tags(self):
"""Test that span.kind OpenTracing tag is mapped to OTel SpanKind."""
test_cases = [
({"span.kind": "consumer"}, SpanKind.CONSUMER),
({"span.kind": "producer"}, SpanKind.PRODUCER),
({"span.kind": "client"}, SpanKind.CLIENT),
({"span.kind": "server"}, SpanKind.SERVER),
({"span.kind": "unknown_kind"}, SpanKind.INTERNAL),
({"other_tag": "value"}, SpanKind.INTERNAL),
(None, SpanKind.INTERNAL),
]

for tags, expected_kind in test_cases:
with self.subTest(tags=tags, expected_kind=expected_kind):
with self.shim.start_active_span(
"TestSpanKind", tags=tags
) as scope:
self.assertEqual(scope.span.unwrap().kind, expected_kind)

def test_span_kind_tag_removed_from_attributes(self):
"""Test that span.kind tag is removed from span attributes after extraction."""
with self.shim.start_active_span(
"TestSpanKind", tags={"span.kind": "client", "other": "value"}
) as scope:
self.assertEqual(scope.span.unwrap().kind, SpanKind.CLIENT)
self.assertNotIn("span.kind", scope.span.unwrap().attributes)
self.assertEqual(scope.span.unwrap().attributes["other"], "value")

def test_mixed_mode(self):
"""Test that span parent-child relationship is kept between
OpenTelemetry and the OpenTracing shim"""
Expand Down
22 changes: 22 additions & 0 deletions shim/opentelemetry-opentracing-shim/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
from opentelemetry.shim.opentracing_shim.util import (
DEFAULT_EVENT_NAME,
event_name_from_kv,
opentracing_kind_to_otel_kind,
time_seconds_from_ns,
time_seconds_to_ns,
)
from opentelemetry.trace import SpanKind


class TestUtil(TestCase):
Expand Down Expand Up @@ -54,6 +56,26 @@ def test_time_seconds_from_ns(self):

self.assertEqual(result, time_nanoseconds / 1e9)

def test_opentracing_kind_to_otel_kind(self):
"""Test mapping of OpenTracing kind tags to OTel SpanKind."""
test_cases = {
"client": SpanKind.CLIENT,
"server": SpanKind.SERVER,
"producer": SpanKind.PRODUCER,
"consumer": SpanKind.CONSUMER,
"internal": SpanKind.INTERNAL,
"unknown": None,
"": None,
}
for opentracing_kind, expected in test_cases.items():
with self.subTest(
opentracing_kind=opentracing_kind, expected=expected
):
self.assertEqual(
opentracing_kind_to_otel_kind(opentracing_kind),
expected,
)

def test_time_conversion_precision(self):
"""Verify time conversion from seconds to nanoseconds and vice versa is
accurate enough.
Expand Down