1111from  importlib .metadata  import  version 
1212from  typing  import  Any , Dict , Mapping , Optional 
1313
14- from  opentelemetry  import  trace 
14+ from  opentelemetry  import  propagate 
15+ from  opentelemetry  import  trace  as  trace_api 
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  NoOpTracerProvider , 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  not  isinstance (tracer_provider , NoOpTracerProvider )
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