@@ -76,6 +76,38 @@ def response_hook(span, service_name, operation_name, result):
7676 )
7777 ec2 = self.session.create_client("ec2", region_name="us-west-2")
7878 ec2.describe_instances()
79+
80+ Extensions
81+ ----------
82+
83+ The instrumentation supports creating extensions for AWS services for enriching what is collected. We have extensions
84+ for the following AWS services:
85+
86+ - Bedrock Runtime
87+ - DynamoDB
88+ - Lambda
89+ - SNS
90+ - SQS
91+
92+ Bedrock Runtime
93+ ***************
94+
95+ This extension implements the GenAI semantic conventions for the following API calls:
96+
97+ - Converse
98+ - ConverseStream
99+ - InvokeModel
100+ - InvokeModelWithResponseStream
101+
102+ For the Converse and ConverseStream APIs tracing, events and metrics are implemented.
103+
104+ For the InvokeModel and InvokeModelWithResponseStream APIs tracing, events and metrics implemented only for a subset of
105+ the available models, namely:
106+ - Amazon Titan models
107+ - Amazon Nova models
108+ - Anthropic Claude
109+
110+ There is no support for tool calls with Amazon Models for the InvokeModel and InvokeModelWithResponseStream APIs.
79111"""
80112
81113import logging
@@ -104,6 +136,7 @@ def response_hook(span, service_name, operation_name, result):
104136 suppress_http_instrumentation ,
105137 unwrap ,
106138)
139+ from opentelemetry .metrics import Instrument , Meter , get_meter
107140from opentelemetry .propagators .aws .aws_xray_propagator import AwsXRayPropagator
108141from opentelemetry .semconv .trace import SpanAttributes
109142from opentelemetry .trace import get_tracer
@@ -134,6 +167,10 @@ def _instrument(self, **kwargs):
134167 self ._tracers = {}
135168 # event_loggers are lazy initialized per-extension in _get_event_logger
136169 self ._event_loggers = {}
170+ # meters are lazy initialized per-extension in _get_meter
171+ self ._meters = {}
172+ # metrics are lazy initialized per-extension in _get_metrics
173+ self ._metrics : Dict [str , Dict [str , Instrument ]] = {}
137174
138175 self .request_hook = kwargs .get ("request_hook" )
139176 self .response_hook = kwargs .get ("response_hook" )
@@ -144,6 +181,7 @@ def _instrument(self, **kwargs):
144181
145182 self .tracer_provider = kwargs .get ("tracer_provider" )
146183 self .event_logger_provider = kwargs .get ("event_logger_provider" )
184+ self .meter_provider = kwargs .get ("meter_provider" )
147185
148186 wrap_function_wrapper (
149187 "botocore.client" ,
@@ -201,6 +239,38 @@ def _get_event_logger(self, extension: _AwsSdkExtension):
201239
202240 return self ._event_loggers [instrumentation_name ]
203241
242+ def _get_meter (self , extension : _AwsSdkExtension ):
243+ """This is a multiplexer in order to have a meter per extension"""
244+
245+ instrumentation_name = self ._get_instrumentation_name (extension )
246+ meter = self ._meters .get (instrumentation_name )
247+ if meter :
248+ return meter
249+
250+ schema_version = extension .meter_schema_version ()
251+ self ._meters [instrumentation_name ] = get_meter (
252+ instrumentation_name ,
253+ "" ,
254+ schema_url = f"https://opentelemetry.io/schemas/{ schema_version } " ,
255+ meter_provider = self .meter_provider ,
256+ )
257+
258+ return self ._meters [instrumentation_name ]
259+
260+ def _get_metrics (
261+ self , extension : _AwsSdkExtension , meter : Meter
262+ ) -> Dict [str , Instrument ]:
263+ """This is a multiplexer for lazy initialization of metrics required by extensions"""
264+ instrumentation_name = self ._get_instrumentation_name (extension )
265+ metrics = self ._metrics .get (instrumentation_name )
266+ if metrics is not None :
267+ return metrics
268+
269+ self ._metrics .setdefault (instrumentation_name , {})
270+ metrics = self ._metrics [instrumentation_name ]
271+ _safe_invoke (extension .setup_metrics , meter , metrics )
272+ return metrics
273+
204274 def _uninstrument (self , ** kwargs ):
205275 unwrap (BaseClient , "_make_api_call" )
206276 unwrap (Endpoint , "prepare_request" )
@@ -244,8 +314,11 @@ def _patched_api_call(self, original_func, instance, args, kwargs):
244314
245315 tracer = self ._get_tracer (extension )
246316 event_logger = self ._get_event_logger (extension )
317+ meter = self ._get_meter (extension )
318+ metrics = self ._get_metrics (extension , meter )
247319 instrumentor_ctx = _BotocoreInstrumentorContext (
248- event_logger = event_logger
320+ event_logger = event_logger ,
321+ metrics = metrics ,
249322 )
250323 with tracer .start_as_current_span (
251324 call_context .span_name ,
0 commit comments