diff --git a/src/strands/telemetry/config.py b/src/strands/telemetry/config.py index 93225335d8..f2122dcded 100644 --- a/src/strands/telemetry/config.py +++ b/src/strands/telemetry/config.py @@ -171,9 +171,36 @@ def setup_otlp_exporter(self, **kwargs: Any) -> "StrandsTelemetry": return self def setup_meter( - self, enable_console_exporter: bool = False, enable_otlp_exporter: bool = False + self, + enable_console_exporter: bool = False, + enable_otlp_exporter: bool = False, + **provider_kwargs: Any, ) -> "StrandsTelemetry": - """Initialize the OpenTelemetry Meter.""" + """Initialize the OpenTelemetry Meter. + + Args: + enable_console_exporter: When True, attach a console metrics exporter. + enable_otlp_exporter: When True, attach an OTLP metrics exporter. + **provider_kwargs: Optional keyword arguments passed directly to + OpenTelemetry's MeterProvider initializer (e.g., views, + shutdown_on_exit). Note that resource and metric_readers are + managed by this method and cannot be overridden via this + parameter. + + Returns: + self: Enables method chaining. + + Example: + Drop high-cardinality attributes (e.g. tool_use_id, event_loop_cycle_id) + from tool metrics by passing a View through to the underlying MeterProvider: + + >>> from opentelemetry.sdk.metrics.view import View + >>> StrandsTelemetry().setup_meter( + ... enable_otlp_exporter=True, + ... views=[View(instrument_name="strands.tool.*", + ... attribute_keys={"tool_name"})], + ... ) + """ logger.info("Initializing meter") metrics_readers = [] try: @@ -190,7 +217,11 @@ def setup_meter( except Exception as e: logger.exception("error=<%s> | Failed to configure OTLP metrics exporter", e) - self.meter_provider = metrics_sdk.MeterProvider(resource=self.resource, metric_readers=metrics_readers) + self.meter_provider = metrics_sdk.MeterProvider( + resource=self.resource, + metric_readers=metrics_readers, + **provider_kwargs, + ) # Set as global tracer provider metrics_api.set_meter_provider(self.meter_provider) diff --git a/tests/strands/telemetry/test_config.py b/tests/strands/telemetry/test_config.py index cc08c295c0..3ee865c090 100644 --- a/tests/strands/telemetry/test_config.py +++ b/tests/strands/telemetry/test_config.py @@ -163,6 +163,25 @@ def test_setup_meter_with_console_and_otlp_exporter( mock_metrics_api.set_meter_provider.assert_called_once() +def test_setup_meter_forwards_provider_kwargs( + mock_resource, + mock_reader, + mock_metrics_api, + mock_meter_provider, +): + """Test that arbitrary kwargs are forwarded to MeterProvider.""" + sentinel_views = [mock.MagicMock()] + + telemetry = StrandsTelemetry() + telemetry.setup_meter(views=sentinel_views) + + mock_meter_provider.assert_called_once_with( + resource=mock_resource.return_value, + metric_readers=[], + views=sentinel_views, + ) + + def test_setup_console_exporter(mock_resource, mock_tracer_provider, mock_console_exporter, mock_simple_processor): """Test add console exporter"""