Add OpenTelemetry metrics exporter built on MetricBuffer · harsh543/sdk-python@3a94445 · GitHub
Skip to content

Commit 3a94445

Browse files
harsh543claude
andcommitted
Add OpenTelemetry metrics exporter built on MetricBuffer
Resolves temporalio#1049 as scoped by @Sushisource: drain a MetricBuffer into a real OTel MeterProvider (views, resources, exemplars all come for free) rather than wiring MetricMeter across a multiprocessing queue. MetricsExporter polls MetricBuffer.retrieve_updates() on a fixed interval and maps buffered updates onto the OTel metrics API: counters via Counter.add() (buffered counter values are deltas), histograms via Histogram.record(), and gauges via create_observable_gauge() backed by a lock-protected last-value cache (OTel invokes gauge callbacks from its own export thread, concurrently with the drain loop). Instrument and attribute objects are cached keyed by id(), exploiting the identity-stability guarantee BufferedMetric/attributes already document. Lifecycle (run/shutdown/async context manager) mirrors Worker's existing asyncio.Event-based shutdown pattern rather than using threads, since that's the only such pattern already in this codebase. Bumps the opentelemetry extra's floor from >=1.11.1 to >=1.12.0 for both api and sdk -- the public opentelemetry.metrics module simply doesn't exist at 1.11.1, confirmed by direct import against the wheel. uv.lock is left untouched; CI resolves it fresh via `uv sync --all-extras` with no --frozen/--locked gate on PR checks. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent add3dcc commit 3a94445

6 files changed

Lines changed: 541 additions & 5 deletions

File tree

‎README.md‎

Lines changed: 33 additions & 0 deletions

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ classifiers = [
2626

2727
[project.optional-dependencies]
2828
grpc = ["grpcio>=1.48.2,<2"]
29-
opentelemetry = ["opentelemetry-api>=1.11.1,<2", "opentelemetry-sdk>=1.11.1,<2"]
29+
opentelemetry = ["opentelemetry-api>=1.12.0,<2", "opentelemetry-sdk>=1.12.0,<2"]
3030
pydantic = ["pydantic>=2.0.0,<3"]
3131
openai-agents = ["openai-agents>=0.17.5", "mcp>=1.9.4, <2"]
3232
google-adk = ["google-adk>=2.2.0,<3", "mcp>=1.24,<2"]

‎temporalio/contrib/opentelemetry/README.md‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
11
# OpenTelemetry Integration for Temporal Python SDK
22

3-
This package provides OpenTelemetry tracing integration for Temporal workflows, activities, and other operations. It includes automatic span creation and propagation for distributed tracing across your Temporal applications.
3+
This package provides OpenTelemetry tracing and metrics integration for Temporal workflows, activities, and other operations. It includes automatic span creation and propagation for distributed tracing, and a `MetricsExporter` for exporting Temporal SDK/Core metrics through the standard OpenTelemetry metrics API, across your Temporal applications.
4+
5+
## Metrics
6+
7+
`MetricsExporter` drains a `temporalio.runtime.MetricBuffer` into an OpenTelemetry `MeterProvider`, so Temporal's own SDK/Core metrics (and any custom metrics recorded via `activity.metric_meter()`/`workflow.metric_meter()`) can be exported through the standard OpenTelemetry metrics pipeline (views, resources, any OTel-compatible backend) instead of only through `PrometheusConfig`/`OpenTelemetryConfig`.
8+
9+
```python
10+
from opentelemetry.sdk.metrics import MeterProvider
11+
from opentelemetry.sdk.metrics.export import ConsoleMetricExporter, PeriodicExportingMetricReader
12+
from temporalio.contrib.opentelemetry import MetricsExporter
13+
from temporalio.runtime import MetricBuffer, Runtime, TelemetryConfig
14+
15+
buffer = MetricBuffer(10_000)
16+
runtime = Runtime(telemetry=TelemetryConfig(metrics=buffer))
17+
meter_provider = MeterProvider(
18+
metric_readers=[PeriodicExportingMetricReader(ConsoleMetricExporter())]
19+
)
20+
21+
async with MetricsExporter(buffer, meter_provider):
22+
client = await Client.connect("localhost:7233", runtime=runtime)
23+
...
24+
```
25+
26+
**Note:** the `Runtime` must be constructed with the buffer attached *before* `MetricsExporter` is started, and the exporter must keep running (it polls on a fixed interval) for as long as metrics should be exported.
427

528
## Overview
629

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
"""OpenTelemetry v2 integration for Temporal SDK.
22
3-
This package provides OpenTelemetry tracing integration for Temporal workflows,
4-
activities, and other operations. It includes automatic span creation and
5-
propagation for distributed tracing.
3+
This package provides OpenTelemetry tracing and metrics integration for
4+
Temporal workflows, activities, and other operations. It includes automatic
5+
span creation and propagation for distributed tracing, and a
6+
:py:class:`MetricsExporter` for exporting Temporal SDK/Core metrics through
7+
the standard OpenTelemetry metrics API.
68
"""
79

810
from temporalio.contrib.opentelemetry._interceptor import (
911
TracingInterceptor,
1012
TracingWorkflowInboundInterceptor,
1113
)
14+
from temporalio.contrib.opentelemetry._metrics_exporter import MetricsExporter
1215
from temporalio.contrib.opentelemetry._otel_interceptor import OpenTelemetryInterceptor
1316
from temporalio.contrib.opentelemetry._plugin import OpenTelemetryPlugin
1417
from temporalio.contrib.opentelemetry._tracer_provider import create_tracer_provider
@@ -18,5 +21,6 @@
1821
"TracingWorkflowInboundInterceptor",
1922
"OpenTelemetryInterceptor",
2023
"OpenTelemetryPlugin",
24+
"MetricsExporter",
2125
"create_tracer_provider",
2226
]
Lines changed: 282 additions & 0 deletions

0 commit comments

Comments
 (0)