1111from importlib .metadata import version
1212from typing import Any , Dict , Mapping , Optional
1313
14- from opentelemetry import trace
14+ import opentelemetry .trace as trace_api
15+ from opentelemetry import propagate
16+ from opentelemetry .baggage .propagation import W3CBaggagePropagator
1517from opentelemetry .exporter .otlp .proto .http .trace_exporter import OTLPSpanExporter
18+ from opentelemetry .propagators .composite import CompositePropagator
1619from opentelemetry .sdk .resources import Resource
17- from opentelemetry .sdk .trace import TracerProvider
20+ from opentelemetry .sdk .trace import TracerProvider as SDKTracerProvider
1821from opentelemetry .sdk .trace .export import BatchSpanProcessor , ConsoleSpanExporter , SimpleSpanProcessor
19- from opentelemetry .trace import StatusCode
22+ from opentelemetry .trace import Span , StatusCode
23+ from opentelemetry .trace .propagation .tracecontext import TraceContextTextMapPropagator
2024
2125from ..agent .agent_result import AgentResult
2226from ..types .content import Message , Messages
@@ -133,16 +137,30 @@ def __init__(
133137
134138 self .service_name = service_name
135139 self .otlp_headers = otlp_headers or {}
136- self .tracer_provider : Optional [TracerProvider ] = None
137- self .tracer : Optional [trace .Tracer ] = None
138-
140+ self .tracer_provider : Optional [trace_api .TracerProvider ] = None
141+ self .tracer : Optional [trace_api .Tracer ] = None
142+
143+ propagate .set_global_textmap (
144+ CompositePropagator (
145+ [
146+ W3CBaggagePropagator (),
147+ TraceContextTextMapPropagator (),
148+ ]
149+ )
150+ )
139151 if self .otlp_endpoint or self .enable_console_export :
152+ # Create our own tracer provider
140153 self ._initialize_tracer ()
141154
142155 def _initialize_tracer (self ) -> None :
143156 """Initialize the OpenTelemetry tracer."""
144157 logger .info ("initializing tracer" )
145158
159+ if self ._is_initialized ():
160+ self .tracer_provider = trace_api .get_tracer_provider ()
161+ self .tracer = self .tracer_provider .get_tracer (self .service_name )
162+ return
163+
146164 # Create resource with service information
147165 resource = Resource .create (
148166 {
@@ -154,7 +172,7 @@ def _initialize_tracer(self) -> None:
154172 )
155173
156174 # Create tracer provider
157- self .tracer_provider = TracerProvider (resource = resource )
175+ self .tracer_provider = SDKTracerProvider (resource = resource )
158176
159177 # Add console exporter if enabled
160178 if self .enable_console_export and self .tracer_provider :
@@ -190,15 +208,19 @@ def _initialize_tracer(self) -> None:
190208 logger .exception ("error=<%s> | Failed to configure OTLP exporter" , e )
191209
192210 # Set as global tracer provider
193- trace .set_tracer_provider (self .tracer_provider )
194- self .tracer = trace .get_tracer (self .service_name )
211+ trace_api .set_tracer_provider (self .tracer_provider )
212+ self .tracer = trace_api .get_tracer (self .service_name )
213+
214+ def _is_initialized (self ) -> bool :
215+ tracer_provider = trace_api .get_tracer_provider ()
216+ return tracer_provider and isinstance (tracer_provider , SDKTracerProvider )
195217
196218 def _start_span (
197219 self ,
198220 span_name : str ,
199- parent_span : Optional [trace . Span ] = None ,
221+ parent_span : Optional [Span ] = None ,
200222 attributes : Optional [Dict [str , AttributeValue ]] = None ,
201- ) -> Optional [trace . Span ]:
223+ ) -> Optional [Span ]:
202224 """Generic helper method to start a span with common attributes.
203225
204226 Args:
@@ -212,7 +234,7 @@ def _start_span(
212234 if self .tracer is None :
213235 return None
214236
215- context = trace .set_span_in_context (parent_span ) if parent_span else None
237+ context = trace_api .set_span_in_context (parent_span ) if parent_span else None
216238 span = self .tracer .start_span (name = span_name , context = context )
217239
218240 # Set start time as a common attribute
@@ -224,7 +246,7 @@ def _start_span(
224246
225247 return span
226248
227- def _set_attributes (self , span : trace . Span , attributes : Dict [str , AttributeValue ]) -> None :
249+ def _set_attributes (self , span : Span , attributes : Dict [str , AttributeValue ]) -> None :
228250 """Set attributes on a span, handling different value types appropriately.
229251
230252 Args:
@@ -239,7 +261,7 @@ def _set_attributes(self, span: trace.Span, attributes: Dict[str, AttributeValue
239261
240262 def _end_span (
241263 self ,
242- span : trace . Span ,
264+ span : Span ,
243265 attributes : Optional [Dict [str , AttributeValue ]] = None ,
244266 error : Optional [Exception ] = None ,
245267 ) -> None :
@@ -278,7 +300,7 @@ def _end_span(
278300 except Exception as e :
279301 logger .warning ("error=<%s> | failed to force flush tracer provider" , e )
280302
281- def end_span_with_error (self , span : trace . Span , error_message : str , exception : Optional [Exception ] = None ) -> None :
303+ def end_span_with_error (self , span : Span , error_message : str , exception : Optional [Exception ] = None ) -> None :
282304 """End a span with error status.
283305
284306 Args:
@@ -294,12 +316,12 @@ def end_span_with_error(self, span: trace.Span, error_message: str, exception: O
294316
295317 def start_model_invoke_span (
296318 self ,
297- parent_span : Optional [trace . Span ] = None ,
319+ parent_span : Optional [Span ] = None ,
298320 agent_name : str = "Strands Agent" ,
299321 messages : Optional [Messages ] = None ,
300322 model_id : Optional [str ] = None ,
301323 ** kwargs : Any ,
302- ) -> Optional [trace . Span ]:
324+ ) -> Optional [Span ]:
303325 """Start a new span for a model invocation.
304326
305327 Args:
@@ -328,7 +350,7 @@ def start_model_invoke_span(
328350 return self ._start_span ("Model invoke" , parent_span , attributes )
329351
330352 def end_model_invoke_span (
331- self , span : trace . Span , message : Message , usage : Usage , error : Optional [Exception ] = None
353+ self , span : Span , message : Message , usage : Usage , error : Optional [Exception ] = None
332354 ) -> None :
333355 """End a model invocation span with results and metrics.
334356
@@ -347,9 +369,7 @@ def end_model_invoke_span(
347369
348370 self ._end_span (span , attributes , error )
349371
350- def start_tool_call_span (
351- self , tool : ToolUse , parent_span : Optional [trace .Span ] = None , ** kwargs : Any
352- ) -> Optional [trace .Span ]:
372+ def start_tool_call_span (self , tool : ToolUse , parent_span : Optional [Span ] = None , ** kwargs : Any ) -> Optional [Span ]:
353373 """Start a new span for a tool call.
354374
355375 Args:
@@ -374,7 +394,7 @@ def start_tool_call_span(
374394 return self ._start_span (span_name , parent_span , attributes )
375395
376396 def end_tool_call_span (
377- self , span : trace . Span , tool_result : Optional [ToolResult ], error : Optional [Exception ] = None
397+ self , span : Span , tool_result : Optional [ToolResult ], error : Optional [Exception ] = None
378398 ) -> None :
379399 """End a tool call span with results.
380400
@@ -402,10 +422,10 @@ def end_tool_call_span(
402422 def start_event_loop_cycle_span (
403423 self ,
404424 event_loop_kwargs : Any ,
405- parent_span : Optional [trace . Span ] = None ,
425+ parent_span : Optional [Span ] = None ,
406426 messages : Optional [Messages ] = None ,
407427 ** kwargs : Any ,
408- ) -> Optional [trace . Span ]:
428+ ) -> Optional [Span ]:
409429 """Start a new span for an event loop cycle.
410430
411431 Args:
@@ -436,7 +456,7 @@ def start_event_loop_cycle_span(
436456
437457 def end_event_loop_cycle_span (
438458 self ,
439- span : trace . Span ,
459+ span : Span ,
440460 message : Message ,
441461 tool_result_message : Optional [Message ] = None ,
442462 error : Optional [Exception ] = None ,
@@ -466,7 +486,7 @@ def start_agent_span(
466486 tools : Optional [list ] = None ,
467487 custom_trace_attributes : Optional [Mapping [str , AttributeValue ]] = None ,
468488 ** kwargs : Any ,
469- ) -> Optional [trace . Span ]:
489+ ) -> Optional [Span ]:
470490 """Start a new span for an agent invocation.
471491
472492 Args:
@@ -506,7 +526,7 @@ def start_agent_span(
506526
507527 def end_agent_span (
508528 self ,
509- span : trace . Span ,
529+ span : Span ,
510530 response : Optional [AgentResult ] = None ,
511531 error : Optional [Exception ] = None ,
512532 ) -> None :
@@ -557,13 +577,16 @@ def get_tracer(
557577 otlp_endpoint: OTLP endpoint URL for sending traces.
558578 otlp_headers: Headers to include with OTLP requests.
559579 enable_console_export: Whether to also export traces to console.
580+ tracer_provider: Optional existing TracerProvider to use instead of creating a new one.
560581
561582 Returns:
562583 The global tracer instance.
563584 """
564585 global _tracer_instance
565586
566- if _tracer_instance is None or (otlp_endpoint and _tracer_instance .otlp_endpoint != otlp_endpoint ): # type: ignore[unreachable]
587+ if (
588+ _tracer_instance is None or (otlp_endpoint and _tracer_instance .otlp_endpoint != otlp_endpoint ) # type: ignore[unreachable]
589+ ):
567590 _tracer_instance = Tracer (
568591 service_name = service_name ,
569592 otlp_endpoint = otlp_endpoint ,
0 commit comments