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
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- `opentelemetry-opentracing-shim`: Map OpenTracing `span.kind` tag to OpenTelemetry SpanKind
([#2549](https://github.com/open-telemetry/opentelemetry-python/issues/2549))
- Fix intermittent CI failures in `getting-started` and `tracecontext` jobs caused by GitHub git CDN SHA propagation lag by installing contrib packages from the already-checked-out local copy instead of a second git clone
([#4958](https://github.com/open-telemetry/opentelemetry-python/pull/4958))
- `opentelemetry-sdk`: fix type annotations on `MetricReader` and related types
Expand All @@ -21,8 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `opentelemetry-sdk`: deprecate `LoggingHandler` in favor of `opentelemetry-instrumentation-logging`, see `opentelemetry-instrumentation-logging` documentation
([#4919](https://github.com/open-telemetry/opentelemetry-python/pull/4919))
- `opentelemetry-sdk`: Clarify log processor error handling expectations in documentation
([#4915](https://github.com/open-telemetry/opentelemetry-python/pull/4915))
- bump semantic-conventions to v1.40.0
([#4941](https://github.com/open-telemetry/opentelemetry-python/pull/4941))
- Add stale PR GitHub Action
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
Tracer,
UnsupportedFormatException,
)
from opentracing import tags as ot_tags
from typing_extensions import deprecated

from opentelemetry.baggage import get_baggage, set_baggage
Expand All @@ -117,6 +118,7 @@
INVALID_SPAN_CONTEXT,
Link,
NonRecordingSpan,
SpanKind,
TracerProvider,
get_current_span,
set_span_in_context,
Expand All @@ -130,6 +132,14 @@
logger = logging.getLogger(__name__)
_SHIM_KEY = create_key("scope_shim")

# Mapping from OpenTracing span kind tag values to OpenTelemetry SpanKind.
_OPENTRACING_TO_OTEL_KIND = {
ot_tags.SPAN_KIND_RPC_CLIENT: SpanKind.CLIENT,
ot_tags.SPAN_KIND_RPC_SERVER: SpanKind.SERVER,
ot_tags.SPAN_KIND_CONSUMER: SpanKind.CONSUMER,
ot_tags.SPAN_KIND_PRODUCER: SpanKind.PRODUCER,
}


def create_tracer(otel_tracer_provider: TracerProvider) -> "TracerShim":
"""Creates a :class:`TracerShim` object from the provided OpenTelemetry
Expand Down Expand Up @@ -674,13 +684,21 @@ def start_span(
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,
context=parent_span_context,
links=valid_links,
attributes=tags,
start_time=start_time_ns,
)
# Extract span kind from OpenTracing tags if present.
# OpenTracing uses the "span.kind" tag to indicate span kind, while
# OpenTelemetry uses a dedicated kind argument.
span_kwargs: dict = {
"context": parent_span_context,
"links": valid_links,
"attributes": tags,
"start_time": start_time_ns,
}
if tags is not None and ot_tags.SPAN_KIND in tags:
span_kwargs["kind"] = _OPENTRACING_TO_OTEL_KIND.get(
tags[ot_tags.SPAN_KIND], SpanKind.INTERNAL
)

span = self._otel_tracer.start_span(operation_name, **span_kwargs)

context = SpanContextShim(span.get_span_context())
return SpanShim(self, context, span)
Expand Down
58 changes: 58 additions & 0 deletions shim/opentelemetry-opentracing-shim/tests/test_shim.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,3 +668,61 @@ def test_mixed_mode(self):
scope.span.unwrap().parent,
opentelemetry_span.context,
)

def test_span_kind_from_tags(self):
"""Test that span.kind OpenTracing tag is converted to OTel SpanKind."""

# Test consumer kind
with self.shim.start_active_span(
"TestSpanKind1", tags={"span.kind": "consumer"}
) as scope:
self.assertEqual(scope.span.unwrap().kind, trace.SpanKind.CONSUMER)

# Test producer kind
with self.shim.start_active_span(
"TestSpanKind2", tags={"span.kind": "producer"}
) as scope:
self.assertEqual(scope.span.unwrap().kind, trace.SpanKind.PRODUCER)

# Test client kind
with self.shim.start_active_span(
"TestSpanKind3", tags={"span.kind": "client"}
) as scope:
self.assertEqual(scope.span.unwrap().kind, trace.SpanKind.CLIENT)

# Test server kind
with self.shim.start_active_span(
"TestSpanKind4", tags={"span.kind": "server"}
) as scope:
self.assertEqual(scope.span.unwrap().kind, trace.SpanKind.SERVER)

# Test unknown kind defaults to INTERNAL
with self.shim.start_active_span(
"TestSpanKind5", tags={"span.kind": "unknown"}
) as scope:
self.assertEqual(scope.span.unwrap().kind, trace.SpanKind.INTERNAL)

# Test no span.kind tag defaults to INTERNAL
with self.shim.start_active_span(
"TestSpanKind6", tags={"foo": "bar"}
) as scope:
self.assertEqual(scope.span.unwrap().kind, trace.SpanKind.INTERNAL)

# Test no tags at all defaults to INTERNAL
with self.shim.start_active_span("TestSpanKind7") as scope:
self.assertEqual(scope.span.unwrap().kind, trace.SpanKind.INTERNAL)

def test_span_kind_tag_preserved_in_attributes(self):
"""Test that span.kind tag is also preserved as an attribute."""

with self.shim.start_active_span(
"TestSpanKindAttr", tags={"span.kind": "consumer", "foo": "bar"}
) as scope:
# Verify the span kind is correctly set
self.assertEqual(scope.span.unwrap().kind, trace.SpanKind.CONSUMER)
# Verify the span.kind tag is preserved as an attribute
self.assertEqual(
scope.span.unwrap().attributes.get("span.kind"), "consumer"
)
# Verify other attributes are also preserved
self.assertEqual(scope.span.unwrap().attributes.get("foo"), "bar")
Loading