Skip to content

Commit b436ca2

Browse files
authored
[Core] Add context kwarg to start_span methods (Azure#41511)
Enables setting the parent span to something other than the current context. Signed-off-by: Paul Van Eck <[email protected]>
1 parent db60732 commit b436ca2

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

sdk/core/azure-core/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Features Added
66

77
- Added a `start_time` keyword argument to the `start_span` and `start_as_current_span` methods in the `OpenTelemetryTracer` class. This allows users to specify a custom start time for created spans. #41106
8+
- Added a `context` keyword argument to the `start_span` and `start_as_current_span` methods in the `OpenTelemetryTracer` class. This allows users to specify a custom parent context for created spans. #41511
89
- Added `is_generated_model` method to `azure.core.serialization`. Returns whether a given input is a model from one of our generated sdks. #41445
910

1011
### Breaking Changes

sdk/core/azure-core/azure/core/tracing/opentelemetry.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from __future__ import annotations
66
from contextlib import contextmanager
77
from contextvars import Token
8-
from typing import Optional, Dict, Sequence, cast, Callable, Iterator, TYPE_CHECKING
8+
from typing import Any, Optional, Dict, Sequence, cast, Callable, Iterator, TYPE_CHECKING
99

1010
from opentelemetry import context as otel_context_module, trace
1111
from opentelemetry.trace import (
@@ -82,6 +82,7 @@ def start_span(
8282
attributes: Optional[Attributes] = None,
8383
links: Optional[Sequence[Link]] = None,
8484
start_time: Optional[int] = None,
85+
context: Optional[Dict[str, Any]] = None,
8586
) -> Span:
8687
"""Starts a span without setting it as the current span in the context.
8788
@@ -95,14 +96,22 @@ def start_span(
9596
:paramtype links: list[~azure.core.tracing.Link]
9697
:keyword start_time: The start time of the span in nanoseconds since the epoch.
9798
:paramtype start_time: Optional[int]
99+
:keyword context: A dictionary of context values corresponding to the parent span. If not provided,
100+
the current global context will be used.
101+
:paramtype context: Optional[Dict[str, any]]
98102
:return: The span that was started
99103
:rtype: ~opentelemetry.trace.Span
100104
"""
101105
otel_kind = _KIND_MAPPINGS.get(kind, OpenTelemetrySpanKind.INTERNAL)
102106
otel_links = self._parse_links(links)
103107

108+
otel_context = None
109+
if context:
110+
otel_context = extract(context)
111+
104112
otel_span = self._tracer.start_span(
105113
name,
114+
context=otel_context,
106115
kind=otel_kind,
107116
attributes=attributes,
108117
links=otel_links,
@@ -121,6 +130,7 @@ def start_as_current_span(
121130
attributes: Optional[Attributes] = None,
122131
links: Optional[Sequence[Link]] = None,
123132
start_time: Optional[int] = None,
133+
context: Optional[Dict[str, Any]] = None,
124134
end_on_exit: bool = True,
125135
) -> Iterator[Span]:
126136
"""Context manager that starts a span and sets it as the current span in the context.
@@ -141,12 +151,17 @@ def start_as_current_span(
141151
:paramtype links: Optional[Sequence[Link]]
142152
:keyword start_time: The start time of the span in nanoseconds since the epoch.
143153
:paramtype start_time: Optional[int]
154+
:keyword context: A dictionary of context values corresponding to the parent span. If not provided,
155+
the current global context will be used.
156+
:paramtype context: Optional[Dict[str, any]]
144157
:keyword end_on_exit: Whether to end the span when exiting the context manager. Defaults to True.
145158
:paramtype end_on_exit: bool
146159
:return: The span that was started
147160
:rtype: Iterator[~opentelemetry.trace.Span]
148161
"""
149-
span = self.start_span(name, kind=kind, attributes=attributes, links=links, start_time=start_time)
162+
span = self.start_span(
163+
name, kind=kind, attributes=attributes, links=links, start_time=start_time, context=context
164+
)
150165
with trace.use_span( # pylint: disable=not-context-manager
151166
span, record_exception=False, end_on_exit=end_on_exit
152167
) as span:

sdk/core/azure-core/tests/test_tracer_otel.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,26 @@ def test_start_span_with_start_time(tracing_helper):
395395
finished_spans = tracing_helper.exporter.get_finished_spans()
396396
assert len(finished_spans) == 2
397397
assert finished_spans[1].start_time == start_time
398+
399+
400+
def test_tracer_with_custom_context(tracing_helper):
401+
"""Test that the tracer can start a span with a custom context."""
402+
tracer = get_tracer()
403+
assert tracer
404+
405+
with tracer.start_as_current_span(name="foo-span") as foo_span:
406+
foo_trace_context = tracer.get_trace_context()
407+
408+
assert "traceparent" in foo_trace_context
409+
410+
with tracer.start_as_current_span(name="bar-span", context=dict(foo_trace_context)) as bar_span:
411+
pass
412+
413+
finished_spans = tracing_helper.exporter.get_finished_spans()
414+
assert len(finished_spans) == 2
415+
assert finished_spans[0].name == "foo-span"
416+
assert finished_spans[1].name == "bar-span"
417+
assert finished_spans[1].context.trace_id == finished_spans[0].context.trace_id
418+
419+
# foo_span should be the parent of bar_span
420+
assert finished_spans[1].parent.span_id == finished_spans[0].context.span_id

0 commit comments

Comments
 (0)