|
6 | 6 |
|
7 | 7 | import json |
8 | 8 | import logging |
9 | | -import os |
10 | 9 | from datetime import date, datetime, timezone |
11 | 10 | from typing import Any, Dict, Mapping, Optional |
12 | 11 |
|
13 | 12 | import opentelemetry.trace as trace_api |
14 | | -from opentelemetry import propagate |
15 | | -from opentelemetry.baggage.propagation import W3CBaggagePropagator |
16 | | -from opentelemetry.propagators.composite import CompositePropagator |
17 | | -from opentelemetry.sdk.trace import TracerProvider as SDKTracerProvider |
18 | | -from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter, SimpleSpanProcessor |
19 | 13 | from opentelemetry.trace import Span, StatusCode |
20 | | -from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator |
21 | 14 |
|
22 | 15 | from ..agent.agent_result import AgentResult |
23 | | -from ..telemetry import get_otel_resource |
24 | 16 | from ..types.content import Message, Messages |
25 | 17 | from ..types.streaming import Usage |
26 | 18 | from ..types.tools import ToolResult, ToolUse |
27 | 19 | from ..types.traces import AttributeValue |
28 | 20 |
|
29 | 21 | logger = logging.getLogger(__name__) |
30 | 22 |
|
31 | | -HAS_OTEL_EXPORTER_MODULE = False |
32 | | -OTEL_EXPORTER_MODULE_ERROR = ( |
33 | | - "opentelemetry-exporter-otlp-proto-http not detected;" |
34 | | - "please install strands-agents with the optional 'otel' target" |
35 | | - "otel http exporting is currently DISABLED" |
36 | | -) |
37 | | -try: |
38 | | - from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter |
39 | | - |
40 | | - HAS_OTEL_EXPORTER_MODULE = True |
41 | | -except ImportError: |
42 | | - pass |
43 | | - |
44 | 23 |
|
45 | 24 | class JSONEncoder(json.JSONEncoder): |
46 | 25 | """Custom JSON encoder that handles non-serializable types.""" |
@@ -106,119 +85,18 @@ class Tracer: |
106 | 85 | def __init__( |
107 | 86 | self, |
108 | 87 | service_name: str = "strands-agents", |
109 | | - otlp_endpoint: Optional[str] = None, |
110 | | - otlp_headers: Optional[Dict[str, str]] = None, |
111 | | - enable_console_export: Optional[bool] = None, |
112 | 88 | ): |
113 | 89 | """Initialize the tracer. |
114 | 90 |
|
115 | 91 | Args: |
116 | 92 | service_name: Name of the service for OpenTelemetry. |
117 | | - otlp_endpoint: OTLP endpoint URL for sending traces. |
118 | | - otlp_headers: Headers to include with OTLP requests. |
119 | | - enable_console_export: Whether to also export traces to console. |
120 | 93 | """ |
121 | | - # Check environment variables first |
122 | | - env_endpoint = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT") |
123 | | - env_console_export_str = os.environ.get("STRANDS_OTEL_ENABLE_CONSOLE_EXPORT") |
124 | | - |
125 | | - # Constructor parameters take precedence over environment variables |
126 | | - self.otlp_endpoint = otlp_endpoint or env_endpoint |
127 | | - |
128 | | - if enable_console_export is not None: |
129 | | - self.enable_console_export = enable_console_export |
130 | | - elif env_console_export_str: |
131 | | - self.enable_console_export = env_console_export_str.lower() in ("true", "1", "yes") |
132 | | - else: |
133 | | - self.enable_console_export = False |
134 | | - |
135 | | - # Parse headers from environment if available |
136 | | - env_headers = os.environ.get("OTEL_EXPORTER_OTLP_HEADERS") |
137 | | - if env_headers: |
138 | | - try: |
139 | | - headers_dict = {} |
140 | | - # Parse comma-separated key-value pairs (format: "key1=value1,key2=value2") |
141 | | - for pair in env_headers.split(","): |
142 | | - if "=" in pair: |
143 | | - key, value = pair.split("=", 1) |
144 | | - headers_dict[key.strip()] = value.strip() |
145 | | - otlp_headers = headers_dict |
146 | | - except Exception as e: |
147 | | - logger.warning("error=<%s> | failed to parse OTEL_EXPORTER_OTLP_HEADERS", e) |
148 | | - |
149 | 94 | self.service_name = service_name |
150 | | - self.otlp_headers = otlp_headers or {} |
151 | 95 | self.tracer_provider: Optional[trace_api.TracerProvider] = None |
152 | 96 | self.tracer: Optional[trace_api.Tracer] = None |
153 | | - propagate.set_global_textmap( |
154 | | - CompositePropagator( |
155 | | - [ |
156 | | - W3CBaggagePropagator(), |
157 | | - TraceContextTextMapPropagator(), |
158 | | - ] |
159 | | - ) |
160 | | - ) |
161 | | - if self.otlp_endpoint or self.enable_console_export: |
162 | | - # Create our own tracer provider |
163 | | - self._initialize_tracer() |
164 | | - |
165 | | - def _initialize_tracer(self) -> None: |
166 | | - """Initialize the OpenTelemetry tracer.""" |
167 | | - logger.info("initializing tracer") |
168 | 97 |
|
169 | | - if self._is_initialized(): |
170 | | - self.tracer_provider = trace_api.get_tracer_provider() |
171 | | - self.tracer = self.tracer_provider.get_tracer(self.service_name) |
172 | | - return |
173 | | - |
174 | | - resource = get_otel_resource() |
175 | | - |
176 | | - # Create tracer provider |
177 | | - self.tracer_provider = SDKTracerProvider(resource=resource) |
178 | | - |
179 | | - # Add console exporter if enabled |
180 | | - if self.enable_console_export and self.tracer_provider: |
181 | | - logger.info("enabling console export") |
182 | | - console_processor = SimpleSpanProcessor(ConsoleSpanExporter()) |
183 | | - self.tracer_provider.add_span_processor(console_processor) |
184 | | - |
185 | | - # Add OTLP exporter if endpoint is provided |
186 | | - if HAS_OTEL_EXPORTER_MODULE and self.otlp_endpoint and self.tracer_provider: |
187 | | - try: |
188 | | - # Ensure endpoint has the right format |
189 | | - endpoint = self.otlp_endpoint |
190 | | - if not endpoint.endswith("/v1/traces") and not endpoint.endswith("/traces"): |
191 | | - if not endpoint.endswith("/"): |
192 | | - endpoint += "/" |
193 | | - endpoint += "v1/traces" |
194 | | - |
195 | | - # Set default content type header if not provided |
196 | | - headers = self.otlp_headers.copy() |
197 | | - if "Content-Type" not in headers: |
198 | | - headers["Content-Type"] = "application/x-protobuf" |
199 | | - |
200 | | - # Create OTLP exporter and processor |
201 | | - otlp_exporter = OTLPSpanExporter( |
202 | | - endpoint=endpoint, |
203 | | - headers=headers, |
204 | | - ) |
205 | | - |
206 | | - batch_processor = BatchSpanProcessor(otlp_exporter) |
207 | | - self.tracer_provider.add_span_processor(batch_processor) |
208 | | - logger.info("endpoint=<%s> | OTLP exporter configured with endpoint", endpoint) |
209 | | - |
210 | | - except Exception as e: |
211 | | - logger.exception("error=<%s> | Failed to configure OTLP exporter", e) |
212 | | - elif self.otlp_endpoint and self.tracer_provider: |
213 | | - raise ModuleNotFoundError(OTEL_EXPORTER_MODULE_ERROR) |
214 | | - |
215 | | - # Set as global tracer provider |
216 | | - trace_api.set_tracer_provider(self.tracer_provider) |
217 | | - self.tracer = trace_api.get_tracer(self.service_name) |
218 | | - |
219 | | - def _is_initialized(self) -> bool: |
220 | | - tracer_provider = trace_api.get_tracer_provider() |
221 | | - return isinstance(tracer_provider, SDKTracerProvider) |
| 98 | + self.tracer_provider = trace_api.get_tracer_provider() |
| 99 | + self.tracer = self.tracer_provider.get_tracer(self.service_name) |
222 | 100 |
|
223 | 101 | def _start_span( |
224 | 102 | self, |
@@ -571,31 +449,20 @@ def end_agent_span( |
571 | 449 |
|
572 | 450 | def get_tracer( |
573 | 451 | service_name: str = "strands-agents", |
574 | | - otlp_endpoint: Optional[str] = None, |
575 | | - otlp_headers: Optional[Dict[str, str]] = None, |
576 | | - enable_console_export: Optional[bool] = None, |
577 | 452 | ) -> Tracer: |
578 | 453 | """Get or create the global tracer. |
579 | 454 |
|
580 | 455 | Args: |
581 | 456 | service_name: Name of the service for OpenTelemetry. |
582 | | - otlp_endpoint: OTLP endpoint URL for sending traces. |
583 | | - otlp_headers: Headers to include with OTLP requests. |
584 | | - enable_console_export: Whether to also export traces to console. |
585 | 457 |
|
586 | 458 | Returns: |
587 | 459 | The global tracer instance. |
588 | 460 | """ |
589 | 461 | global _tracer_instance |
590 | 462 |
|
591 | | - if ( |
592 | | - _tracer_instance is None or (otlp_endpoint and _tracer_instance.otlp_endpoint != otlp_endpoint) # type: ignore[unreachable] |
593 | | - ): |
| 463 | + if not _tracer_instance: |
594 | 464 | _tracer_instance = Tracer( |
595 | 465 | service_name=service_name, |
596 | | - otlp_endpoint=otlp_endpoint, |
597 | | - otlp_headers=otlp_headers, |
598 | | - enable_console_export=enable_console_export, |
599 | 466 | ) |
600 | 467 |
|
601 | 468 | return _tracer_instance |
|
0 commit comments