For AI agents: A markdown version of this page is available at https://docs.datadoghq.com/opentelemetry/integrations/runtime_metrics.md. A documentation index is available at /llms.txt.

OpenTelemetry Runtime Metrics

Overview

Runtime metrics provide insights into application performance, including memory usage, garbage collection, and parallelization. Datadog SDKs offer runtime metrics collection for each supported language, and OpenTelemetry (OTel) also collects compatible runtime metrics that can be sent to Datadog through the OpenTelemetry SDKs.

Compatibility

Datadog supports OpenTelemetry runtime metrics for the following languages:

  • Java
  • .NET
  • Go
  • Node.js
  • Python

For details about host and container metrics mapping, see OpenTelemetry Metrics Mapping.

Setup instructions

1. Prerequisites

2. Configure your application

Select your language to see instructions for configuring the OpenTelemetry SDK to send runtime metrics:

Note: Runtime metrics are only exported if a MeterProvider and metric exporter are configured. Set the OTEL_METRICS_EXPORTER environment variable or programmatically configure a metricReader in your SDK initialization. For Go, Node.js, and Python, the MeterProvider must be configured manually; Java and .NET auto-configure it via their auto-instrumentation agents.

Automatic instrumentation

If you use OpenTelemetry automatic instrumentation for Java applications, runtime metrics are enabled by default.

Manual instrumentation

If you use OpenTelemetry manual instrumentation, follow the guides for your Java version:

Experimental telemetry

Enabling experimental OpenTelemetry runtime telemetry may provide additional metric mappings between Datadog and OpenTelemetry for Java. To enable it, set the following environment variable:

OTEL_INSTRUMENTATION_RUNTIME_TELEMETRY_EMIT_EXPERIMENTAL_TELEMETRY=true

Additional JMX metrics

To collect additional JVM metrics beyond the default runtime instrumentation, install the OpenTelemetry JMX Metric Scraper. The scraper scrapes MBeans over JMX and emits them as OpenTelemetry metrics, which Datadog then maps to runtime metrics (see the JVM Contrib table in Data collected).

Configure the scraper with otel.jmx.target.source=legacy to collect these additional metrics. The scraper’s instrumentation source emits the same semantic-convention metrics already produced natively by the OpenTelemetry Java SDK, so it does not provide additional coverage.

Collector configuration

The jvm.gc.collections.count and jvm.gc.collections.elapsed metrics require the Delta-to-Rate Processor in the OpenTelemetry Collector. Set OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta or use the cumulativetodelta processor.

processors:
  deltatorate:
    metrics:
      - jvm.gc.collections.count
      - jvm.gc.collections.elapsed

Note: The minimum supported version of the OpenTelemetry Java agent is 2.0.0.

Manual instrumentation

OpenTelemetry Go applications are instrumented manually. To enable runtime metrics, see the documentation for the runtime package.

Collector configuration

Some Go runtime metrics are reported as monotonic sums, but Datadog expects them as gauges. The Transform Processor converts these sums to gauges, and the Cumulative-to-Delta Processor excludes them from delta conversion. Verify that OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is not set to delta. Otherwise, metrics excluded by cumulativetodelta are ignored.

processors:
  transform/go-runtime:
    error_mode: ignore
    metric_statements:
      - context: metric
        statements:
          - convert_sum_to_gauge() where name == "process.runtime.go.gc.pause_total_ns" or name == "process.runtime.go.gc.count" or name == "go.memory.allocated" or name == "go.memory.allocations"

  cumulativetodelta:
    exclude:
      metrics:
        - process.runtime.go.gc.pause_total_ns
        - process.runtime.go.gc.count
        - go.memory.allocated
        - go.memory.allocations
      match_type: strict

Note: The minimum supported version of go.opentelemetry.io/contrib/instrumentation/runtime is v0.46.0, which also requires Go 1.20+ and OpenTelemetry Go SDK v1.21.0+.

Automatic instrumentation

If you use OpenTelemetry automatic instrumentation for .NET applications, runtime metrics are enabled by default.

Manual instrumentation

If you use OpenTelemetry manual instrumentation, see the documentation for the OpenTelemetry.Instrumentation.Runtime library.

Metric export interval

The default metric export interval for the .NET OTel SDK differs from the default for the Datadog .NET SDK. Datadog recommends setting the OTEL_METRIC_EXPORT_INTERVAL environment variable on your .NET service to match the default Datadog metric export interval:

OTEL_METRIC_EXPORT_INTERVAL=10000

Collector configuration

The dotnet.process.cpu.time and process.cpu.time metrics require the Delta-to-Rate Processor in the OpenTelemetry Collector. Set OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta or use the cumulativetodelta processor.

processors:
  deltatorate:
    metrics:
      - dotnet.process.cpu.time
      - process.cpu.time

Note: The minimum supported version of the .NET OpenTelemetry SDK is 1.5.0.

Automatic instrumentation

If you use OpenTelemetry automatic instrumentation for Node.js applications, runtime metrics are enabled by default through the @opentelemetry/instrumentation-runtime-node package.

Manual instrumentation

If you use OpenTelemetry manual instrumentation, see the documentation for the @opentelemetry/instrumentation-runtime-node library.

Host metrics

Host-level metrics such as system CPU and memory usage are not included in OpenTelemetry automatic instrumentation. To collect these metrics:

  1. Install and configure the @opentelemetry/host-metrics package:

    npm install @opentelemetry/host-metrics
    
  2. Initialize the package with your existing MeterProvider:

    const { HostMetrics } = require('@opentelemetry/host-metrics');
    const { metrics } = require('@opentelemetry/api');
    const hostMetrics = new HostMetrics({
      meterProvider: metrics.getMeterProvider(),
    });
    hostMetrics.start();
    

For the list of metrics collected by this package, see the Node.js Contrib Host table.

Note: The minimum supported version of @opentelemetry/instrumentation-runtime-node is 0.9.0.

Installation

Runtime metrics are not enabled by default for Python applications. Install the opentelemetry-instrumentation-system-metrics package:

pip install opentelemetry-instrumentation-system-metrics

Automatic instrumentation

If you use OpenTelemetry automatic instrumentation for Python applications, opentelemetry-instrument discovers and enables the package after installation.

Manual instrumentation

If you use OpenTelemetry manual instrumentation, enable the package in your application:

from opentelemetry.instrumentation.system_metrics import SystemMetricsInstrumentor

SystemMetricsInstrumentor().instrument()

View runtime metric dashboards

After setup is complete, you can view runtime metrics in:

  • The service’s details page (see Java example below)
  • The flame graph metrics tab
  • Default runtime dashboards (Java Example)
Service page showing OpenTelemetry runtime metrics on the JVM Metrics tab

Data collected

The following tables list the OpenTelemetry runtime metrics collected for Datadog’s out-of-the-box in-app experiences, along with a description and any attribute conditions (Filter) that Datadog uses to identify the correct data point.

For Collector processor configuration required to make these metrics compatible with Datadog, see the Collector configuration instructions above.

JVM Instrumentation

These metrics are collected when using the latest version of the OpenTelemetry Java SDK.

OTELDESCRIPTIONFILTER
jvm.buffer.countNumber of buffers in the pool.jvm.buffer.pool.name: direct
jvm.buffer.countNumber of buffers in the pool.jvm.buffer.pool.name: mapped
jvm.buffer.memory.limitMeasure of total memory capacity of buffers.jvm.buffer.pool.name: direct
jvm.buffer.memory.limitMeasure of total memory capacity of buffers.jvm.buffer.pool.name: mapped
jvm.buffer.memory.usedMeasure of memory used by buffers.jvm.buffer.pool.name: direct
jvm.buffer.memory.usedMeasure of memory used by buffers.jvm.buffer.pool.name: mapped
jvm.class.countNumber of classes currently loaded.
jvm.cpu.recent_utilizationRecent CPU utilization for the process as reported by the JVM. Note: The value range is [0.0,1.0]. This utilization is not defined as being for the specific interval since last measurement (unlike system.cpu.utilization). Reference.
jvm.file_descriptor.countNumber of open file descriptors as reported by the JVM.
jvm.memory.usedMeasure of memory used.jvm.memory.pool.name: g1_old_gen, zgc_old_generation, tenured_gen, ps_old_gen, cms_old_gen
jvm.memory.type: heap
jvm.memory.usedMeasure of memory used.jvm.memory.pool.name: g1_eden_space, zgc_young_generation, eden_space, ps_eden_space, par_eden_space
jvm.memory.type: heap
jvm.memory.usedMeasure of memory used.jvm.memory.pool.name: g1_survivor_space, survivor_space, ps_survivor_space, par_survivor_space
jvm.memory.type: heap
jvm.memory.usedMeasure of memory used.jvm.memory.pool.name: metaspace
jvm.memory.type: non_heap
jvm.system.cpu.utilizationRecent CPU utilization for the whole system as reported by the JVM. Note: The value range is [0.0,1.0]. This utilization is not defined as being for the specific interval since last measurement (unlike system.cpu.utilization). Reference.

JVM Contrib

These metrics are collected when using the OpenTelemetry JMX Metric Scraper.

OTELDESCRIPTIONFILTER
jvm.classes.loadedThe number of loaded classes
jvm.gc.collections.countThe total number of garbage collections that have occurredname: copy, ps_scavenge, parnew, g1_young_generation, zgc_minor_cycles, zgc_minor_pauses
jvm.gc.collections.countThe total number of garbage collections that have occurredname: marksweepcompact, ps_marksweep, concurrentmarksweep, g1_mixed_generation, g1_old_generation, shenandoah_cycles, zgc_major_cycles, zgc_major_pauses
jvm.gc.collections.elapsedThe approximate accumulated collection elapsed timename: copy, ps_scavenge, parnew, g1_young_generation, zgc_minor_cycles, zgc_minor_pauses
jvm.gc.collections.elapsedThe approximate accumulated collection elapsed timename: marksweepcompact, ps_marksweep, concurrentmarksweep, g1_mixed_generation, g1_old_generation, shenandoah_cycles, zgc_major_cycles, zgc_major_pauses
jvm.memory.heap.committedThe amount of memory that is guaranteed to be available for the heap
jvm.memory.heap.initThe initial amount of memory that the JVM requests from the operating system for the heap
jvm.memory.heap.maxThe maximum amount of memory can be used for the heap
jvm.memory.heap.usedThe current heap memory usage
jvm.memory.nonheap.committedThe amount of memory that is guaranteed to be available for non-heap purposes
jvm.memory.nonheap.initThe initial amount of memory that the JVM requests from the operating system for non-heap purposes
jvm.memory.nonheap.maxThe maximum amount of memory can be used for non-heap purposes
jvm.memory.nonheap.usedThe current non-heap memory usage
jvm.memory.pool.usedThe current memory pool memory usagename: metaspace
jvm.memory.pool.usedThe current memory pool memory usagename: g1_old_gen, zgc_old_generation, tenured_gen, ps_old_gen, cms_old_gen
jvm.memory.pool.usedThe current memory pool memory usagename: g1_eden_space, zgc_young_generation, eden_space, ps_eden_space, par_eden_space
jvm.memory.pool.usedThe current memory pool memory usagename: g1_survivor_space, survivor_space, ps_survivor_space, par_survivor_space
jvm.threads.countThe current number of threads

Deprecated JVM Metrics

These metrics are collected when using OpenTelemetry Java SDK versions 1.32.0 and earlier.

OTELDESCRIPTIONFILTER
process.runtime.jvm.buffer.countNumber of buffers in the pool.pool: direct
process.runtime.jvm.buffer.countNumber of buffers in the pool.pool: mapped
process.runtime.jvm.buffer.usageMeasure of memory used by buffers.pool: direct
process.runtime.jvm.buffer.usageMeasure of memory used by buffers.pool: mapped
process.runtime.jvm.classes.current_loadedNumber of classes currently loaded.
process.runtime.jvm.cpu.utilizationRecent CPU utilization for the process. Note: The value range is [0.0,1.0]. This utilization is not defined as being for the specific interval since last measurement (unlike system.cpu.utilization). Reference.
process.runtime.jvm.memory.usageMeasure of memory used.pool: g1_old_gen, zgc_old_generation, tenured_gen, ps_old_gen, cms_old_gen
type: heap
process.runtime.jvm.memory.usageMeasure of memory used.pool: g1_eden_space, zgc_young_generation, eden_space, ps_eden_space, par_eden_space
type: heap
process.runtime.jvm.memory.usageMeasure of memory used.pool: g1_survivor_space, survivor_space, ps_survivor_space, par_survivor_space
type: heap
process.runtime.jvm.memory.usageMeasure of memory used.pool: metaspace
type: non_heap
process.runtime.jvm.system.cpu.utilizationRecent CPU utilization for the whole system as reported by the JVM. Note: The value range is [0.0,1.0]. This utilization is not defined as being for the specific interval since last measurement (unlike system.cpu.utilization). Reference.

Go Runtime Metrics

These metrics are collected by the OpenTelemetry Go runtime instrumentation package.

OTELDESCRIPTION
go.config.gogcHeap size target percentage configured by the user, otherwise 100. Note: The value range is [0.0,100.0]. Computed from /gc/gogc:percent.
go.goroutine.countCount of live goroutines. Note: Computed from /sched/goroutines:goroutines.
go.memory.allocatedMemory allocated to the heap by the application. Note: Computed from /gc/heap/allocs:bytes.
go.memory.allocationsCount of allocations to the heap by the application. Note: Computed from /gc/heap/allocs:objects.
go.memory.gc.goalHeap size target for the end of the GC cycle. Note: Computed from /gc/heap/goal:bytes.
go.memory.limitGo runtime memory limit configured by the user, if a limit exists. Note: Computed from /gc/gomemlimit:bytes. This metric is excluded if the limit obtained from the Go runtime is math.MaxInt64.
go.processor.limitThe number of OS threads that can execute user-level Go code simultaneously. Note: Computed from /sched/gomaxprocs:threads.
process.runtime.go.cgo.callsNumber of cgo calls made by the current process
process.runtime.go.gc.countNumber of completed garbage collection cycles
process.runtime.go.gc.pause_total_nsCumulative nanoseconds in GC stop-the-world pauses since the program started
process.runtime.go.goroutinesNumber of goroutines that currently exist
process.runtime.go.mem.heap_allocBytes of allocated heap objects
process.runtime.go.mem.heap_idleBytes in idle (unused) spans
process.runtime.go.mem.heap_inuseBytes in in-use spans
process.runtime.go.mem.heap_objectsNumber of allocated heap objects
process.runtime.go.mem.heap_releasedBytes of idle spans whose physical memory has been returned to the OS
process.runtime.go.mem.heap_sysBytes of heap memory obtained from the OS

.NET System.Runtime

These metrics are emitted by the .NET runtime's built-in System.Runtime meter on .NET 9.0 and later. The OpenTelemetry SDK collects and exports them automatically.

OTELDESCRIPTIONFILTER
dotnet.gc.last_collection.heap.sizeThe managed GC heap size (including fragmentation), as observed during the latest garbage collection. Note: Meter name: System.Runtime; Added in: .NET 9.0. This metric reports the same values as calling GC.GetGCMemoryInfo().GenerationInfo.SizeAfterBytes.gc.heap.generation: gen0
dotnet.gc.last_collection.heap.sizeThe managed GC heap size (including fragmentation), as observed during the latest garbage collection. Note: Meter name: System.Runtime; Added in: .NET 9.0. This metric reports the same values as calling GC.GetGCMemoryInfo().GenerationInfo.SizeAfterBytes.gc.heap.generation: gen1
dotnet.gc.last_collection.heap.sizeThe managed GC heap size (including fragmentation), as observed during the latest garbage collection. Note: Meter name: System.Runtime; Added in: .NET 9.0. This metric reports the same values as calling GC.GetGCMemoryInfo().GenerationInfo.SizeAfterBytes.gc.heap.generation: gen2
dotnet.gc.last_collection.heap.sizeThe managed GC heap size (including fragmentation), as observed during the latest garbage collection. Note: Meter name: System.Runtime; Added in: .NET 9.0. This metric reports the same values as calling GC.GetGCMemoryInfo().GenerationInfo.SizeAfterBytes.gc.heap.generation: loh
dotnet.process.cpu.timeCPU time used by the process. Note: Meter name: System.Runtime; Added in: .NET 9.0. This metric reports the same values as accessing the corresponding processor time properties on System.Diagnostics.Process.cpu.mode: user
dotnet.process.cpu.timeCPU time used by the process. Note: Meter name: System.Runtime; Added in: .NET 9.0. This metric reports the same values as accessing the corresponding processor time properties on System.Diagnostics.Process.cpu.mode: system

.NET Contrib Runtime

These metrics are collected by the OpenTelemetry.Instrumentation.Runtime package. On .NET 9.0 and later, these overlap with the System.Runtime metrics above.

OTELDESCRIPTIONFILTER
process.runtime.dotnet.gc.heap.sizeThe heap size (including fragmentation), as observed during thegeneration: gen0
process.runtime.dotnet.gc.heap.sizeThe heap size (including fragmentation), as observed during thegeneration: gen1
process.runtime.dotnet.gc.heap.sizeThe heap size (including fragmentation), as observed during thegeneration: gen2
process.runtime.dotnet.gc.heap.sizeThe heap size (including fragmentation), as observed during thegeneration: loh
process.runtime.dotnet.thread_pool.threads.countThe number of thread pool threads that currently exist.

.NET Contrib Process

These metrics are collected by the OpenTelemetry.Instrumentation.Process package.

OTELDESCRIPTION
process.thread.countProcess threads count.

Node.js Contrib Runtime

These metrics are emitted from auto-instrumentation with the latest version of the OpenTelemetry Node.js SDK.

OTELDESCRIPTION
nodejs.eventloop.utilizationEvent loop utilization. Note: The value range is [0.0, 1.0] and can be retrieved from performance.eventLoopUtilization([utilization1[, utilization2]])
v8js.memory.heap.limitTotal heap memory size pre-allocated. Note: The value can be retrieved from value space_size of v8.getHeapSpaceStatistics()
v8js.memory.heap.space.available_sizeHeap space available size. Note: Value can be retrieved from value space_available_size of v8.getHeapSpaceStatistics()
v8js.memory.heap.space.physical_sizeCommitted size of a heap space. Note: Value can be retrieved from value physical_space_size of v8.getHeapSpaceStatistics()
v8js.memory.heap.usedHeap Memory size allocated. Note: The value can be retrieved from value space_used_size of v8.getHeapSpaceStatistics()

Node.js Contrib Host

These metrics are collected by the @opentelemetry/host-metrics package. This package is not included in OpenTelemetry automatic instrumentation and must be installed and configured manually.

OTELDESCRIPTIONFILTER
process.memory.usageThe amount of physical memory in use.
system.memory.usageBytes of memory in use.
system.memory.usageBytes of memory in use.state: free, cached, buffered
system.memory.usageBytes of memory in use.state: free
system.memory.usageBytes of memory in use.system.memory.state: free

Python Runtime Metrics

These metrics are collected by the opentelemetry-instrumentation-system-metrics package. The following table lists the conceptual equivalences between OpenTelemetry and Datadog Python runtime metrics. There are no direct metric-name mappings because the metric types differ between the two systems.

OTELDatadogDescriptionFilter
process.cpu.timeruntime.python.cpu.time.sysNumber of seconds executing in the kernel.type: system
process.cpu.timeruntime.python.cpu.time.userNumber of seconds executing outside the kernel.type: user
process.cpu.utilizationruntime.python.cpu.percentCPU utilization percentage. OTel divides the raw value by 100 times the number of CPU cores.
process.context_switchesruntime.python.cpu.ctx_switch.voluntaryNumber of voluntary context switches.type: voluntary
process.context_switchesruntime.python.cpu.ctx_switch.involuntaryNumber of involuntary context switches.type: involuntary
process.runtime.{python_implementation}.gc_countruntime.python.gc.count.gen0Number of generation 0 objects.count: 0
process.runtime.{python_implementation}.gc_countruntime.python.gc.count.gen1Number of generation 1 objects.count: 1
process.runtime.{python_implementation}.gc_countruntime.python.gc.count.gen2Number of generation 2 objects.count: 2
process.memory.usageruntime.python.mem.rssResident set memory.
process.thread.countruntime.python.thread_countNumber of threads.

Troubleshooting

Metric name mapping

OpenTelemetry runtime metrics are mapped to Datadog by metric name. Do not rename host metrics for OpenTelemetry runtime metrics as this breaks the mapping.

Further reading

Additional helpful documentation, links, and articles: