Skip to content

Commit e4331da

Browse files
committed
More metrics setup
1 parent 762b798 commit e4331da

File tree

3 files changed

+83
-3
lines changed

3 files changed

+83
-3
lines changed

instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def response_hook(span, service_name, operation_name, result):
104104
suppress_http_instrumentation,
105105
unwrap,
106106
)
107-
from opentelemetry.metrics import get_meter
107+
from opentelemetry.metrics import Instrument, Meter, get_meter
108108
from opentelemetry.propagators.aws.aws_xray_propagator import AwsXRayPropagator
109109
from opentelemetry.semconv.trace import SpanAttributes
110110
from opentelemetry.trace import get_tracer
@@ -137,6 +137,8 @@ def _instrument(self, **kwargs):
137137
self._event_loggers = {}
138138
# meters are lazy initialized per-extension in _get_meter
139139
self._meters = {}
140+
# metrics are lazy initial per-extension in _get_metrics
141+
self._metrics: dict[str, dict[str, Instrument]] = {}
140142

141143
self.request_hook = kwargs.get("request_hook")
142144
self.response_hook = kwargs.get("response_hook")
@@ -223,6 +225,20 @@ def _get_meter(self, extension: _AwsSdkExtension):
223225

224226
return self._meters[instrumentation_name]
225227

228+
def _get_metrics(
229+
self, extension: _AwsSdkExtension, meter: Meter
230+
) -> dict[str, Instrument]:
231+
"""This is a multiplexer for lazy initial metrics required by extensions"""
232+
instrumentation_name = self._get_instrumentation_name(extension)
233+
metrics = self._metrics.get(instrumentation_name)
234+
if metrics is not None:
235+
return metrics
236+
237+
self._metrics.setdefault(instrumentation_name, {})
238+
metrics = self._metrics[instrumentation_name]
239+
_safe_invoke(extension.setup_metrics, meter, metrics)
240+
return metrics
241+
226242
def _uninstrument(self, **kwargs):
227243
unwrap(BaseClient, "_make_api_call")
228244
unwrap(Endpoint, "prepare_request")
@@ -266,8 +282,11 @@ def _patched_api_call(self, original_func, instance, args, kwargs):
266282

267283
tracer = self._get_tracer(extension)
268284
event_logger = self._get_event_logger(extension)
285+
meter = self._get_meter(extension)
286+
metrics = self._get_metrics(extension, meter)
269287
instrumentor_ctx = _BotocoreInstrumentorContext(
270-
event_logger=event_logger
288+
event_logger=event_logger,
289+
metrics=metrics,
271290
)
272291
with tracer.start_as_current_span(
273292
call_context.span_name,

instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/bedrock.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,13 @@
3939
_BotoClientErrorT,
4040
_BotocoreInstrumentorContext,
4141
)
42+
from opentelemetry.metrics import Instrument, Meter
4243
from opentelemetry.semconv._incubating.attributes.error_attributes import (
4344
ERROR_TYPE,
4445
)
4546
from opentelemetry.semconv._incubating.attributes.gen_ai_attributes import (
47+
GEN_AI_CLIENT_OPERATION_DURATION,
48+
GEN_AI_CLIENT_TOKEN_USAGE,
4649
GEN_AI_OPERATION_NAME,
4750
GEN_AI_REQUEST_MAX_TOKENS,
4851
GEN_AI_REQUEST_MODEL,
@@ -61,6 +64,40 @@
6164

6265
_logger = logging.getLogger(__name__)
6366

67+
_GEN_AI_CLIENT_OPERATION_DURATION_BUCKETS = [
68+
0.01,
69+
0.02,
70+
0.04,
71+
0.08,
72+
0.16,
73+
0.32,
74+
0.64,
75+
1.28,
76+
2.56,
77+
5.12,
78+
10.24,
79+
20.48,
80+
40.96,
81+
81.92,
82+
]
83+
84+
_GEN_AI_CLIENT_TOKEN_USAGE_BUCKETS = [
85+
1,
86+
4,
87+
16,
88+
64,
89+
256,
90+
1024,
91+
4096,
92+
16384,
93+
65536,
94+
262144,
95+
1048576,
96+
4194304,
97+
16777216,
98+
67108864,
99+
]
100+
64101
_MODEL_ID_KEY: str = "modelId"
65102

66103

@@ -88,6 +125,20 @@ def should_end_span_on_exit(self):
88125
not in self._DONT_CLOSE_SPAN_ON_END_OPERATIONS
89126
)
90127

128+
def setup_metrics(self, meter: Meter, metrics: dict[str, Instrument]):
129+
metrics[GEN_AI_CLIENT_OPERATION_DURATION] = meter.create_histogram(
130+
name=GEN_AI_CLIENT_OPERATION_DURATION,
131+
description="GenAI operation duration",
132+
unit="s",
133+
explicit_bucket_boundaries_advisory=_GEN_AI_CLIENT_OPERATION_DURATION_BUCKETS,
134+
)
135+
metrics[GEN_AI_CLIENT_TOKEN_USAGE] = meter.create_histogram(
136+
name=GEN_AI_CLIENT_TOKEN_USAGE,
137+
description="Measures number of input and output tokens used",
138+
unit="{token}",
139+
explicit_bucket_boundaries_advisory=_GEN_AI_CLIENT_TOKEN_USAGE_BUCKETS,
140+
)
141+
91142
def extract_attributes(self, attributes: _AttributeMapT):
92143
if self._call_context.operation not in self._HANDLED_OPERATIONS:
93144
return

instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/types.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from typing import Any, Dict, Optional, Tuple
1717

1818
from opentelemetry._events import EventLogger
19+
from opentelemetry.metrics import Instrument, Meter
1920
from opentelemetry.trace import SpanKind
2021
from opentelemetry.trace.span import Span
2122
from opentelemetry.util.types import AttributeValue
@@ -91,8 +92,11 @@ def _get_attr(obj, name: str, default=None):
9192

9293

9394
class _BotocoreInstrumentorContext:
94-
def __init__(self, event_logger: EventLogger):
95+
def __init__(
96+
self, event_logger: EventLogger, metrics: dict[str, Instrument]
97+
):
9598
self.event_logger = event_logger
99+
self.metrics = metrics
96100

97101

98102
class _AwsSdkExtension:
@@ -130,6 +134,12 @@ def should_end_span_on_exit(self) -> bool: # pylint:disable=no-self-use
130134
"""
131135
return True
132136

137+
def setup_metrics(self, meter: Meter, metrics: dict[str, Instrument]):
138+
"""Callback which gets invoked to setup metrics.
139+
140+
Extensions might override this function to add to the metrics dictionary all the metrics
141+
they want to receive later in _BotocoreInstrumentorContext."""
142+
133143
def extract_attributes(self, attributes: _AttributeMapT):
134144
"""Callback which gets invoked before the span is created.
135145

0 commit comments

Comments
 (0)