Repository navigation
feat(opentelemetry): export runtime metrics over OTLP - #21610
MilanGarnier wants to merge 1 commit into
Conversation
Codeowners resolved asResolved from the full PR diff against |
Dependency direction analysis🚨 New dependency direction violations detected 🚨1 new violation(s) of the dependency direction rules have been introduced by this PR:
|
❌ ErrorsYour PR has failed checks. Please review the issues below and take necessary action before merging. 🚦 2 Pipeline jobs failed
ℹ️ InfoNo other issues found (see more)🧪 All tests passed Useful? React with 👍 / 👎 This comment will be updated automatically if new data arrives.🔗 Commit SHA: fd9c5dc | Docs | View more details | Give us feedback! |
BenchmarksBenchmark execution time: 2026-11-09 17:27:12 Comparing candidate commit fd9c5dc in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 606 metrics, 9 unstable metrics, 1 flaky benchmarks without significant changes.
|
Description
When both
DD_RUNTIME_METRICS_ENABLED=trueandDD_METRICS_OTEL_ENABLED=trueare set, Python runtime metrics are now exported over OTLP through the OpenTelemetry metrics API instead of being sent over DogStatsD.The instruments are registered on the meter
datadog.python.runtimeand follow the names, units and attributes ofopentelemetry-instrumentation-system-metrics:process.cpu.timestype:system/userprocess.cpu.utilization1process.context_switches{context_switch}type:voluntary/involuntary(unsupported types omitted)process.memory.usageByprocess.thread.count{thread}cpython.gc.collections{collection}cpython.gc.generationcpython.gc.collected_objects{object}cpython.gc.generationcpython.gc.uncollectable_objects{object}cpython.gc.generationprocess.runtime.cpython.gc_count{object}countHow it works:
RuntimeWorkerstill starts at bootstrap. In OpenTelemetry mode its first periodic run (not bootstrap) callsotlp_runtime_metrics.start(), which sets up the ddtrace MeterProvider (once, through the newensure_otel_meter_provider()) and registers the instruments. Deferring to the worker thread keeps the OpenTelemetry SDK and exporter out of the preload phase, so they are not unloaded by the bootstrap module cleanup and are imported after an application's geventpatch_all().dogstatsd_urlis ignored (logged at debug level). DogStatsD flushes are skipped while the OTLP start is pending, so the two paths never both report.RuntimeWorker.disable()makes the callbacks observe nothing; re-enabling reuses the registered instruments.Testing
New tests in
tests/opentelemetry/test_metrics.py:ddtrace-runover gRPC and HTTP/protobuf, checking the metric names, the meter scope, the absence ofruntime.python.*names, and that the SDK is not imported at bootstrap;InMemoryMetricReader, plus disable/re-enable anddogstatsd_urlbeing ignored;DD_RUNTIME_METRICS_ENABLED×DD_METRICS_OTEL_ENABLED×OTEL_METRICS_EXPORTER=none;patch_all().The OpenTelemetry suite passes across the OpenTelemetry SDK versions in the test matrix. One
tracersuite test (test_runtime_worker_flush_keeps_automatic_gc_running) fails locally on a DogStatsD "Connection refused" stderr line; it fails the same way onmain.Risks
process.runtime.cpython.gc_countis reported as an ObservableCounter, as upstream does, butgc.get_count()drops after each collection, so cumulative-to-delta conversion can produce negative values for it.runtime.python.gc.pause*) have no OpenTelemetry equivalent and are not exported in OTLP mode.patch_all()later than that would import the SDK before patching.OTEL_SDK_DISABLED=trueis not handled here. It will be addressed in a separate change.Additional Notes
The upstream system metrics instrumentation is not used directly because it depends on
psutil; the values come from the existing native process metrics collector andgc.🤖 Generated with Claude Code