Skip to content

Commit 6a8a4fa

Browse files
anuraagaxrmx
andauthored
chore(util-genai): migrate handler metrics test to TestBase (#4332)
* chore(util-genai): migrate handler metrics test to TestBase * Formatting --------- Co-authored-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
1 parent cf9979a commit 6a8a4fa

1 file changed

Lines changed: 22 additions & 50 deletions

File tree

util/opentelemetry-util-genai/tests/test_handler_metrics.py

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,22 @@
11
from __future__ import annotations
22

3-
from typing import Any, Dict, List, Tuple
4-
from unittest import TestCase
3+
from typing import Any, Dict, List
54
from unittest.mock import patch
65

7-
from opentelemetry.sdk.metrics import MeterProvider
8-
from opentelemetry.sdk.metrics.export import InMemoryMetricReader
9-
from opentelemetry.sdk.trace import TracerProvider
10-
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
11-
from opentelemetry.sdk.trace.export.in_memory_span_exporter import (
12-
InMemorySpanExporter,
13-
)
146
from opentelemetry.semconv._incubating.attributes import (
157
gen_ai_attributes as GenAI,
168
)
179
from opentelemetry.semconv.schemas import Schemas
10+
from opentelemetry.test.test_base import TestBase
1811
from opentelemetry.util.genai.handler import TelemetryHandler
1912
from opentelemetry.util.genai.types import Error, LLMInvocation
2013

2114
_DEFAULT_SCHEMA_URL = Schemas.V1_37_0.value
2215

16+
SCOPE = "opentelemetry.util.genai.handler"
2317

24-
class TelemetryHandlerMetricsTest(TestCase):
25-
def setUp(self) -> None:
26-
self.metric_reader = InMemoryMetricReader()
27-
self.meter_provider = MeterProvider(
28-
metric_readers=[self.metric_reader]
29-
)
30-
self.span_exporter = InMemorySpanExporter()
31-
self.tracer_provider = TracerProvider()
32-
self.tracer_provider.add_span_processor(
33-
SimpleSpanProcessor(self.span_exporter)
34-
)
3518

19+
class TelemetryHandlerMetricsTest(TestBase):
3620
def test_stop_llm_records_duration_and_tokens(self) -> None:
3721
handler = TelemetryHandler(
3822
tracer_provider=self.tracer_provider,
@@ -52,10 +36,8 @@ def test_stop_llm_records_duration_and_tokens(self) -> None:
5236
):
5337
handler.stop_llm(invocation)
5438

55-
metrics, resource_metrics = self._harvest_metrics()
56-
self._assert_metric_scope_schema_urls(
57-
resource_metrics, _DEFAULT_SCHEMA_URL
58-
)
39+
self._assert_metric_scope_schema_urls(_DEFAULT_SCHEMA_URL)
40+
metrics = self._harvest_metrics()
5941
self.assertIn("gen_ai.client.operation.duration", metrics)
6042
duration_points = metrics["gen_ai.client.operation.duration"]
6143
self.assertEqual(len(duration_points), 1)
@@ -110,10 +92,8 @@ def test_stop_llm_records_duration_and_tokens_with_additional_attributes(
11092
invocation.attributes = {"should not be on metrics": "value"}
11193
handler.stop_llm(invocation)
11294

113-
metrics, resource_metrics = self._harvest_metrics()
114-
self._assert_metric_scope_schema_urls(
115-
resource_metrics, _DEFAULT_SCHEMA_URL
116-
)
95+
self._assert_metric_scope_schema_urls(_DEFAULT_SCHEMA_URL)
96+
metrics = self._harvest_metrics()
11797
self.assertIn("gen_ai.client.operation.duration", metrics)
11898
duration_points = metrics["gen_ai.client.operation.duration"]
11999
self.assertIn("gen_ai.client.token.usage", metrics)
@@ -148,10 +128,8 @@ def test_fail_llm_records_error_and_available_tokens(self) -> None:
148128
):
149129
handler.fail_llm(invocation, error)
150130

151-
metrics, resource_metrics = self._harvest_metrics()
152-
self._assert_metric_scope_schema_urls(
153-
resource_metrics, _DEFAULT_SCHEMA_URL
154-
)
131+
self._assert_metric_scope_schema_urls(_DEFAULT_SCHEMA_URL)
132+
metrics = self._harvest_metrics()
155133
self.assertIn("gen_ai.client.operation.duration", metrics)
156134
duration_points = metrics["gen_ai.client.operation.duration"]
157135
self.assertEqual(len(duration_points), 1)
@@ -177,35 +155,29 @@ def test_fail_llm_records_error_and_available_tokens(self) -> None:
177155

178156
def _harvest_metrics(
179157
self,
180-
) -> Tuple[Dict[str, List[Any]], List[Any]]:
158+
) -> Dict[str, List[Any]]:
181159
"""Returns (metrics_by_name, resource_metrics).
182160
183161
metrics_by_name maps metric name to list of data points.
184162
resource_metrics is the raw ResourceMetrics list for scope-level
185163
assertions (e.g. schema_url).
186164
"""
187-
try:
188-
self.meter_provider.force_flush()
189-
except Exception: # pylint: disable=broad-except
190-
assert False, "force_flush raised an exception"
191-
self.metric_reader.collect()
165+
metrics = self.get_sorted_metrics(SCOPE)
192166
metrics_by_name: Dict[str, List[Any]] = {}
193-
metrics_data = self.metric_reader.get_metrics_data()
194-
resource_metrics = (
195-
metrics_data and metrics_data.resource_metrics
196-
) or []
197-
for resource_metric in resource_metrics:
198-
for scope_metric in resource_metric.scope_metrics or []:
199-
for metric in scope_metric.metrics or []:
200-
points = metric.data.data_points or []
201-
metrics_by_name.setdefault(metric.name, []).extend(points)
202-
return metrics_by_name, resource_metrics
167+
for metric in metrics or []:
168+
points = metric.data.data_points or []
169+
metrics_by_name.setdefault(metric.name, []).extend(points)
170+
return metrics_by_name
203171

204172
def _assert_metric_scope_schema_urls(
205-
self, resource_metrics: List[Any], expected_schema_url: str
173+
self, expected_schema_url: str
206174
) -> None:
207-
for resource_metric in resource_metrics:
175+
for (
176+
resource_metric
177+
) in self.memory_metrics_reader.get_metrics_data().resource_metrics:
208178
for scope_metric in resource_metric.scope_metrics:
179+
if scope_metric.scope.name != SCOPE:
180+
continue
209181
self.assertEqual(
210182
scope_metric.scope.schema_url, expected_schema_url
211183
)

0 commit comments

Comments
 (0)