|
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