11
11
from importlib .metadata import version
12
12
from typing import Any , Dict , Mapping , Optional
13
13
14
- from opentelemetry import trace
14
+ import opentelemetry .trace as trace_api
15
+ from opentelemetry import propagate
16
+ from opentelemetry .baggage .propagation import W3CBaggagePropagator
15
17
from opentelemetry .exporter .otlp .proto .http .trace_exporter import OTLPSpanExporter
18
+ from opentelemetry .propagators .composite import CompositePropagator
16
19
from opentelemetry .sdk .resources import Resource
17
- from opentelemetry .sdk .trace import TracerProvider
20
+ from opentelemetry .sdk .trace import TracerProvider as SDKTracerProvider
18
21
from 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
20
24
21
25
from ..agent .agent_result import AgentResult
22
26
from ..types .content import Message , Messages
@@ -133,16 +137,30 @@ def __init__(
133
137
134
138
self .service_name = service_name
135
139
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
+ )
139
151
if self .otlp_endpoint or self .enable_console_export :
152
+ # Create our own tracer provider
140
153
self ._initialize_tracer ()
141
154
142
155
def _initialize_tracer (self ) -> None :
143
156
"""Initialize the OpenTelemetry tracer."""
144
157
logger .info ("initializing tracer" )
145
158
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
+
146
164
# Create resource with service information
147
165
resource = Resource .create (
148
166
{
@@ -154,7 +172,7 @@ def _initialize_tracer(self) -> None:
154
172
)
155
173
156
174
# Create tracer provider
157
- self .tracer_provider = TracerProvider (resource = resource )
175
+ self .tracer_provider = SDKTracerProvider (resource = resource )
158
176
159
177
# Add console exporter if enabled
160
178
if self .enable_console_export and self .tracer_provider :
@@ -190,15 +208,19 @@ def _initialize_tracer(self) -> None:
190
208
logger .exception ("error=<%s> | Failed to configure OTLP exporter" , e )
191
209
192
210
# 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 isinstance (tracer_provider , SDKTracerProvider )
195
217
196
218
def _start_span (
197
219
self ,
198
220
span_name : str ,
199
- parent_span : Optional [trace . Span ] = None ,
221
+ parent_span : Optional [Span ] = None ,
200
222
attributes : Optional [Dict [str , AttributeValue ]] = None ,
201
- ) -> Optional [trace . Span ]:
223
+ ) -> Optional [Span ]:
202
224
"""Generic helper method to start a span with common attributes.
203
225
204
226
Args:
@@ -212,7 +234,7 @@ def _start_span(
212
234
if self .tracer is None :
213
235
return None
214
236
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
216
238
span = self .tracer .start_span (name = span_name , context = context )
217
239
218
240
# Set start time as a common attribute
@@ -224,7 +246,7 @@ def _start_span(
224
246
225
247
return span
226
248
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 :
228
250
"""Set attributes on a span, handling different value types appropriately.
229
251
230
252
Args:
@@ -239,7 +261,7 @@ def _set_attributes(self, span: trace.Span, attributes: Dict[str, AttributeValue
239
261
240
262
def _end_span (
241
263
self ,
242
- span : trace . Span ,
264
+ span : Span ,
243
265
attributes : Optional [Dict [str , AttributeValue ]] = None ,
244
266
error : Optional [Exception ] = None ,
245
267
) -> None :
@@ -272,13 +294,13 @@ def _end_span(
272
294
finally :
273
295
span .end ()
274
296
# Force flush to ensure spans are exported
275
- if self .tracer_provider :
297
+ if self .tracer_provider and hasattr ( self . tracer_provider , 'force_flush' ) :
276
298
try :
277
299
self .tracer_provider .force_flush ()
278
300
except Exception as e :
279
301
logger .warning ("error=<%s> | failed to force flush tracer provider" , e )
280
302
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 :
282
304
"""End a span with error status.
283
305
284
306
Args:
@@ -294,12 +316,12 @@ def end_span_with_error(self, span: trace.Span, error_message: str, exception: O
294
316
295
317
def start_model_invoke_span (
296
318
self ,
297
- parent_span : Optional [trace . Span ] = None ,
319
+ parent_span : Optional [Span ] = None ,
298
320
agent_name : str = "Strands Agent" ,
299
321
messages : Optional [Messages ] = None ,
300
322
model_id : Optional [str ] = None ,
301
323
** kwargs : Any ,
302
- ) -> Optional [trace . Span ]:
324
+ ) -> Optional [Span ]:
303
325
"""Start a new span for a model invocation.
304
326
305
327
Args:
@@ -328,7 +350,7 @@ def start_model_invoke_span(
328
350
return self ._start_span ("Model invoke" , parent_span , attributes )
329
351
330
352
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
332
354
) -> None :
333
355
"""End a model invocation span with results and metrics.
334
356
@@ -347,9 +369,7 @@ def end_model_invoke_span(
347
369
348
370
self ._end_span (span , attributes , error )
349
371
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 ]:
353
373
"""Start a new span for a tool call.
354
374
355
375
Args:
@@ -374,7 +394,7 @@ def start_tool_call_span(
374
394
return self ._start_span (span_name , parent_span , attributes )
375
395
376
396
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
378
398
) -> None :
379
399
"""End a tool call span with results.
380
400
@@ -402,10 +422,10 @@ def end_tool_call_span(
402
422
def start_event_loop_cycle_span (
403
423
self ,
404
424
event_loop_kwargs : Any ,
405
- parent_span : Optional [trace . Span ] = None ,
425
+ parent_span : Optional [Span ] = None ,
406
426
messages : Optional [Messages ] = None ,
407
427
** kwargs : Any ,
408
- ) -> Optional [trace . Span ]:
428
+ ) -> Optional [Span ]:
409
429
"""Start a new span for an event loop cycle.
410
430
411
431
Args:
@@ -436,7 +456,7 @@ def start_event_loop_cycle_span(
436
456
437
457
def end_event_loop_cycle_span (
438
458
self ,
439
- span : trace . Span ,
459
+ span : Span ,
440
460
message : Message ,
441
461
tool_result_message : Optional [Message ] = None ,
442
462
error : Optional [Exception ] = None ,
@@ -466,7 +486,7 @@ def start_agent_span(
466
486
tools : Optional [list ] = None ,
467
487
custom_trace_attributes : Optional [Mapping [str , AttributeValue ]] = None ,
468
488
** kwargs : Any ,
469
- ) -> Optional [trace . Span ]:
489
+ ) -> Optional [Span ]:
470
490
"""Start a new span for an agent invocation.
471
491
472
492
Args:
@@ -506,7 +526,7 @@ def start_agent_span(
506
526
507
527
def end_agent_span (
508
528
self ,
509
- span : trace . Span ,
529
+ span : Span ,
510
530
response : Optional [AgentResult ] = None ,
511
531
error : Optional [Exception ] = None ,
512
532
) -> None :
@@ -557,13 +577,16 @@ def get_tracer(
557
577
otlp_endpoint: OTLP endpoint URL for sending traces.
558
578
otlp_headers: Headers to include with OTLP requests.
559
579
enable_console_export: Whether to also export traces to console.
580
+ tracer_provider: Optional existing TracerProvider to use instead of creating a new one.
560
581
561
582
Returns:
562
583
The global tracer instance.
563
584
"""
564
585
global _tracer_instance
565
586
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
+ ):
567
590
_tracer_instance = Tracer (
568
591
service_name = service_name ,
569
592
otlp_endpoint = otlp_endpoint ,
0 commit comments