Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3275](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3275))
- `opentelemetry-instrumentation-botocore` Add support for GenAI tool events
([#3302](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3302))
- `opentelemetry-instrumentation-botocore` Add support for GenAI metrics
([#3326](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3326))
- `opentelemetry-instrumentation` make it simpler to initialize auto-instrumentation programmatically
([#3273](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3273))
- Add `opentelemetry-instrumentation-vertexai>=2.0b0` to `opentelemetry-bootstrap`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ classifiers = [
"Programming Language :: Python :: 3.13",
]
dependencies = [
"opentelemetry-api ~= 1.12",
"opentelemetry-api ~= 1.30",
"opentelemetry-instrumentation == 0.52b0.dev",
"opentelemetry-semantic-conventions == 0.52b0.dev",
"opentelemetry-propagator-aws-xray ~= 1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,38 @@ def response_hook(span, service_name, operation_name, result):
)
ec2 = self.session.create_client("ec2", region_name="us-west-2")
ec2.describe_instances()

Extensions
----------

The instrumentation supports creating extensions for AWS services for enriching what is collected. We have extensions
for the following AWS services:

- Bedrock Runtime
- DynamoDB
- Lambda
- SNS
- SQS

Bedrock Runtime
***************

This extension implements the GenAI semantic conventions for the following API calls:

- Converse
- ConverseStream
- InvokeModel
- InvokeModelWithResponseStream

For the Converse and ConverseStream APIs tracing, events and metrics are implemented.

For the InvokeModel and InvokeModelWithResponseStream APIs tracing, events and metrics implemented only for a subset of
the available models, namely:
- Amazon Titan models
- Amazon Nova models
- Anthropic Claude

There is no support for tool calls with Amazon Models for the InvokeModel and InvokeModelWithResponseStream APIs.
"""

import logging
Expand Down Expand Up @@ -104,6 +136,7 @@ def response_hook(span, service_name, operation_name, result):
suppress_http_instrumentation,
unwrap,
)
from opentelemetry.metrics import Instrument, Meter, get_meter
from opentelemetry.propagators.aws.aws_xray_propagator import AwsXRayPropagator
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.trace import get_tracer
Expand Down Expand Up @@ -134,6 +167,10 @@ def _instrument(self, **kwargs):
self._tracers = {}
# event_loggers are lazy initialized per-extension in _get_event_logger
self._event_loggers = {}
# meters are lazy initialized per-extension in _get_meter
self._meters = {}
# metrics are lazy initialized per-extension in _get_metrics
self._metrics: Dict[str, Dict[str, Instrument]] = {}

self.request_hook = kwargs.get("request_hook")
self.response_hook = kwargs.get("response_hook")
Expand All @@ -144,6 +181,7 @@ def _instrument(self, **kwargs):

self.tracer_provider = kwargs.get("tracer_provider")
self.event_logger_provider = kwargs.get("event_logger_provider")
self.meter_provider = kwargs.get("meter_provider")

wrap_function_wrapper(
"botocore.client",
Expand Down Expand Up @@ -201,6 +239,38 @@ def _get_event_logger(self, extension: _AwsSdkExtension):

return self._event_loggers[instrumentation_name]

def _get_meter(self, extension: _AwsSdkExtension):
"""This is a multiplexer in order to have a meter per extension"""

instrumentation_name = self._get_instrumentation_name(extension)
meter = self._meters.get(instrumentation_name)
if meter:
return meter

schema_version = extension.meter_schema_version()
self._meters[instrumentation_name] = get_meter(
instrumentation_name,
"",
schema_url=f"https://opentelemetry.io/schemas/{schema_version}",
meter_provider=self.meter_provider,
)

return self._meters[instrumentation_name]

def _get_metrics(
self, extension: _AwsSdkExtension, meter: Meter
) -> Dict[str, Instrument]:
"""This is a multiplexer for lazy initialization of metrics required by extensions"""
instrumentation_name = self._get_instrumentation_name(extension)
metrics = self._metrics.get(instrumentation_name)
if metrics is not None:
return metrics

self._metrics.setdefault(instrumentation_name, {})
metrics = self._metrics[instrumentation_name]
_safe_invoke(extension.setup_metrics, meter, metrics)
return metrics

def _uninstrument(self, **kwargs):
unwrap(BaseClient, "_make_api_call")
unwrap(Endpoint, "prepare_request")
Expand Down Expand Up @@ -244,8 +314,11 @@ def _patched_api_call(self, original_func, instance, args, kwargs):

tracer = self._get_tracer(extension)
event_logger = self._get_event_logger(extension)
meter = self._get_meter(extension)
metrics = self._get_metrics(extension, meter)
instrumentor_ctx = _BotocoreInstrumentorContext(
event_logger=event_logger
event_logger=event_logger,
metrics=metrics,
)
with tracer.start_as_current_span(
call_context.span_name,
Expand Down
Loading