> ## Documentation Index
> Fetch the complete documentation index at: https://launchdarkly.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Recording metrics

<View title="Developer" />

<View title="Federal docs" />

<View title="EU docs" />

The observability plugin provides different functions depending on what kind of data you want to record.

The recorded data is available as an `$ld:telemetry:metric` event. To learn more, read [Observability autogenerated metrics](/docs/home/metrics/autogen/observability).

You can view all metrics sent to LaunchDarkly under **Metrics** in the LaunchDarkly user interface. To learn more, read [Metrics](/docs/home/metrics).

## How metrics are aggregated and exported

The observability SDK plugins use the OpenTelemetry SDK to aggregate and export metrics. Understanding when and how metrics are aggregated can help you tune performance and interpret metric data correctly.

### Aggregation temporality

All LaunchDarkly observability SDKs use **cumulative** aggregation temporality, which is the OpenTelemetry SDK default. This means each export includes the cumulative value since the SDK was initialized, rather than a delta since the last export. LaunchDarkly's backend handles the conversion to display rate-based or windowed views in the UI.

### How metrics roll up

Metrics with the same name and identical attribute sets are automatically aggregated by the OpenTelemetry SDK before export. The aggregation strategy depends on the instrument type:

| Metric type | OTel instrument | Aggregation |
| - | - | - |
| `recordMetric` / `recordGauge` | Gauge | Last value wins |
| `recordCount` | Counter | Sum of all recorded values |
| `recordIncr` | Counter | Sum of increments |
| `recordHistogram` | Histogram | Distribution (bucket counts, sum, min, max) |
| `recordUpDownCounter` | UpDownCounter | Net sum (increments and decrements) |

This means if you record two `recordCount` calls with the name `"page-views"` and the same attributes within a single export interval, the SDK exports a single aggregated data point with the sum of both values.

To learn more, read the OpenTelemetry documentation about the [Metrics Data Model](https://opentelemetry.io/docs/specs/otel/metrics/data-model/).

### Export intervals by SDK

Each SDK periodically flushes aggregated metrics to LaunchDarkly. The export interval varies by SDK:

| SDK | Metrics export interval | Traces/logs export interval |
| - | - | - |
| JavaScript (browser) | 30 seconds | 30 seconds |
| Node.js (server-side) | 5 seconds | 5 seconds |
| Python | 5 seconds | 5 seconds |
| Go | 5 seconds | 1 second (traces) |
| .NET (server-side) | 5 seconds | 5 seconds |
| Ruby | 60 seconds | 1 second |
| React Native | 10 seconds | 500 milliseconds |
| Android | 10 seconds | 1 second |

<Info>
  **Browser SDKs use longer intervals**

  Client-side browser SDKs use a 30-second export interval to reduce network overhead for end users. Server-side SDKs use shorter intervals (typically 5 seconds) for more real-time visibility. These intervals are not currently configurable through the plugin options.
</Info>

### Using exemplars to link traces and sessions

LaunchDarkly stores references from a recorded measurement back to the trace or session that produced it. These references are called exemplars, and you can overlay them on a metric graph to open the span or session replay behind a given metric value. To learn more, read [Metric exemplars](/docs/home/observability/metric-exemplars).

There is no exemplar setting to configure, and you do not need to construct an OpenTelemetry `MeterProvider` of your own. The plugin owns the meter, and LaunchDarkly attaches whichever references are available when it ingests the metric. What you control is whether those references exist:

* Session references are automatic, but require session replay in addition to observability. The browser, Android, and React Native plugins tag every metric they record with the current session identifier, and session replay creates the session that reference points to. The iOS plugin does not add a session identifier to metrics. Also, server-side metrics do not carry a session identifier unless your service receives one from the client that originated the request.
* Trace references require that your application record the measurement inside an active span. Because the OpenTelemetry SDK samples the reference from the active context at the time of the measurement, a metric recorded outside of a span arrives with no trace reference. To learn more about creating spans, read [Recording traces](/docs/sdk/features/observability-traces).

Trace references are the standard OpenTelemetry exemplar mechanism rather than a LaunchDarkly feature, so their availability and configuration depend on the OpenTelemetry SDK for your language. To learn more, read the OpenTelemetry documentation on [exemplar filters and reservoirs](https://opentelemetry.io/docs/specs/otel/metrics/sdk/#exemplar).

Details about each SDK's configuration are available in the SDK-specific sections below.

## Client-side SDKs

This feature is available in the observability plugin for the following client-side SDKs:

* [iOS](#ios)
* [Android](#android)
* [JavaScript](#javascript)
* [React Native](#react-native)
* [React Web](#react-web)
* [Vue](#vue)

### iOS

<Accordion title="Expand iOS code sample">
  When you record a metric with the observability plugin, it must include a `name` and `value`. Optionally, it can include `attributes` and a `timestamp`. To construct the attributes, use `Attributes` from the [`@opentelemetry/api`](https://opentelemetry.io/docs/specs/semconv/general/attributes/).

  Here are the options for recording metrics:

  <CodeGroup>
    ```swift title="Record point-in-time" lines wrap theme={null}
      LDObserve.shared.recordMetric(metric: .init(name: "elapsedTimeMs", value: 2200))
    ```

    ```swift title="Record cumulative count" lines wrap theme={null}
      LDObserve.shared.recordCount(metric: .init(name: "example-event-name", value: 42))
    ```

    ```swift title="Record cumulative increment" lines wrap theme={null}
      LDObserve.shared.recordIncr(metric: .init(name: "example-counter", value: 15))
    ```

    ```swift title="Record point-in-time, aggregate to histogram" lines wrap theme={null}
      LDObserve.shared.recordHistogram(metric: .init(name: "work.difficulty", value: 7.8))
    ```

    ```swift title="Record counter" lines wrap theme={null}
      LDObserve.shared.recordUpDownCounter(metric: .init(name: "users", value: 2))
    ```
  </CodeGroup>

  To learn more, read [`Observe`](https://github.com/launchdarkly/swift-launchdarkly-observability/blob/main/Sources/LaunchDarklyOtel/API/Observe.swift).
</Accordion>

### Android

<Accordion title="Expand Android code sample">
  When you record a metric with the observability plugin, it must include a `name` and `value`. Optionally, it can include `attributes` and a `timestamp`. To construct the attributes, use `Attributes` from the [`@opentelemetry/api`](https://opentelemetry.io/docs/specs/semconv/general/attributes/).

  Here are the options for recording metrics:

  <CodeGroup>
    ```java title="Record point-in-time" lines wrap theme={null}
      LDObserve.recordMetric(Metric("elapsedTimeMs", 2200))
    ```

    ```java title="Record cumulative count" lines wrap theme={null}
      LDObserve.recordCount(Metric("example-event-name", 42))
    ```

    ```java title="Record cumulative increment" lines wrap theme={null}
      LDObserve.recordIncr(Metric("example-counter", 15))
    ```

    ```java title="Record point-in-time, aggregate to histogram" lines wrap theme={null}
      LDObserve.recordHistogram(Metric("work.difficulty", 7.8))
    ```

    ```java title="Record counter" lines wrap theme={null}
      LDObserve.recordUpDownCounter(Metric("users", 2))
    ```
  </CodeGroup>

  To learn more, read [`LDObserve`](https://launchdarkly.github.io/observability-sdk/sdk/@launchdarkly/observability-android/com/launchdarkly/observability/sdk/LDObserve.html).
</Accordion>

### JavaScript

<Accordion title="Expand JavaScript code sample">
  Here are the options for recording metrics:

  <CodeGroup>
    ```js title="Record point-in-time" lines wrap theme={null}
    const onClick = () => {
      const start = Date.now();
      doInterestingWork();
      const elapsed = Date.now() - start;
      LDObserve.recordGauge({name: "elapsedTimeMs", value: elapsed});
    };
    ```

    ```js title="Record cumulative count" lines wrap theme={null}
    const onClick = () => {
      LDObserve.recordCount({name: "example-event-name", value: 42});
    };
    ```

    ```js title="Record cumulative increment" lines wrap theme={null}
    const onClick = () => {
      doInterestingWork();
      LDObserve.recordIncr({name: "example-counter"});
    };
    ```

    ```js title="Record point-in-time, aggregate to histogram" lines wrap theme={null}
    const onClick = () => {
      doInterestingWork();
      // measure some value about the code path
      const difficulty = 1.23;
      LDObserve.recordHistogram({name: "work.difficulty", value: difficulty});
    };
    ```

    ```js title="Record counter" lines wrap theme={null}
    // a counter metric may be incremented or decremented
    const onClick = () => {
      const isActive = checkUserActivity();
      const value = isActive ? 1 : -1;
      LDObserve.recordUpDownCounter({name: "users", value: value});
    };
    ```
  </CodeGroup>

  To learn more, read [`Observe`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_observe.Observe.html).
</Accordion>

### React Native

<Accordion title="Expand React Native code sample">
  When you record a metric with the observability plugin, it must include a `name` and `value`. Optionally, it can include `attributes` and a `timestamp`. To construct the attributes, use `Attributes` from the [`@opentelemetry/api`](https://opentelemetry.io/docs/specs/semconv/general/attributes/).

  Here are the options for recording metrics:

  <CodeGroup>
    ```js title="Record point-in-time" lines wrap theme={null}
      LDObserve.recordMetric({name: "elapsedTimeMs", value: 2200});
    ```

    ```js title="Record cumulative count" lines wrap theme={null}
      LDObserve.recordCount({name: "example-event-name", value: 42});
    ```

    ```js title="Record cumulative increment" lines wrap theme={null}
      LDObserve.recordIncr({name: "example-counter", value: 15});
    ```

    ```js title="Record point-in-time, aggregate to histogram" lines wrap theme={null}
      LDObserve.recordHistogram({name: "work.difficulty", value: 7.8});
    ```

    ```js title="Record counter" lines wrap theme={null}
      LDObserve.recordUpDownCounter({name: "users", value: 2});
    ```
  </CodeGroup>

  To learn more, read [`Observe`](https://launchdarkly.github.io/observability-sdk/sdk/@launchdarkly/observability-react-native/interfaces/Observe.html).
</Accordion>

### React Web

To record metrics with the React Web SDK, follow the example for [JavaScript](#javascript).

### Vue

To record metrics with the Vue SDK, follow the example for [JavaScript](#javascript).

## Server-side SDKs

This feature is available in the observability plugin for the following server-side SDKs:

* [.NET (server-side)](#net-server-side)
* [Go](#go)
* [Node.js (server-side)](#node-js-server-side)
* [Python](#python)

### .NET (server-side)

<Accordion title="Expand .NET (server-side) code sample">
  Here are the options for recording metrics:

  <CodeGroup>
    ```csharp title="Record point-in-time" lines wrap theme={null}
      Observe.RecordMetric(name, value, attributes);
    ```

    ```csharp title="Record cumulative count" lines wrap theme={null}
      Observe.RecordCount(name, value, attributes);
    ```

    ```csharp title="Record cumulative increment" lines wrap theme={null}
      Observe.RecordIncr(name, attributes);
    ```

    ```csharp title="Record point-in-time, aggregate to histogram" lines wrap theme={null}
      Observe.RecordHistogram(name, value, attributes);
    ```

    ```csharp title="Record counter" lines wrap theme={null}
      // a counter metric may be incremented or decremented
      Observe.RecordUpDownCounter(name, delta, attributes);
    ```
  </CodeGroup>

  To learn more, read [`Observe`](https://launchdarkly.github.io/observability-sdk/sdk/@launchdarkly/observability-dotnet/api/LaunchDarkly.Observability.Observe.html).
</Accordion>

### Go

<Accordion title="Expand Go code sample">
  To record a metric, pass the Go `context.Context`, as well as the name, value, and optional attributes of the metric to the appropriate `Record*` function. For example, you might want to record the value for a point-in-time measurement, such as the current CPU utilization percentage, or for a counter, such as the number of cache hits. The optional attributes may include any [attributes from the OpenTelemetry specification](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#KeyValue).

  Metrics with the same name and attributes are aggregated using the OpenTelemetry SDK. To learn more, read the OTel documentation on the [Metrics Data Model](https://opentelemetry.io/docs/specs/otel/metrics/data-model/).

  Here are the options for recording metrics:

  <CodeGroup>
    ```go title="Record point-in-time" lines wrap theme={null}
      ldobserve.RecordMetric(ctx, "example-metric-name", 3.7)
    ```

    ```go title="Record cumulative count" lines wrap theme={null}
      ldobserve.RecordCount(ctx, "example-metric-name", 42)
    ```

    ```go title="Record point-in-time, aggregate to histogram" lines wrap theme={null}
      ldobserve.RecordHistogram(ctx, "example-metric-name", 3.7)
    ```
  </CodeGroup>

  To learn more, read [`RecordMetric`](https://pkg.go.dev/github.com/launchdarkly/observability-sdk/go#RecordMetric), [`RecordCount`](https://pkg.go.dev/github.com/launchdarkly/observability-sdk/go#RecordCount), and [`RecordHistogram`](https://pkg.go.dev/github.com/launchdarkly/observability-sdk/go#RecordHistogram).
</Accordion>

### Node.js (server-side)

<Accordion title="Expand Node.js (server-side) code sample">
  To record a metric, first create the metric within your application. The `Metric` interface includes a `name`, `value`, and optional `tags`. For example, you might create a metric for a point-in-time measurement, such as the current CPU utilization percentage, or for a counter, such as the number of cache hits.

  Values with the same metric name and attributes are aggregated using the OpenTelemetry SDK. To learn more, read the OTel documentation on the [Metrics Data Model](https://opentelemetry.io/docs/specs/otel/metrics/data-model/).

  <CodeGroup>
    ```js title="Create OTel metric" lines wrap theme={null}
    const metric = {
      name: "exampleMetric",
      value: 42
    }
    ```
  </CodeGroup>

  Here are the options for recording metrics:

  <CodeGroup>
    ```js title="Record point-in-time" lines wrap theme={null}
      LDObserve.recordMetric(metric);
    ```

    ```js title="Record cumulative count" lines wrap theme={null}
      LDObserve.recordCount(metric);
    ```

    ```js title="Record cumulative increment" lines wrap theme={null}
      LDObserve.recordIncr(metric);
    ```

    ```js title="Record point-in-time, aggregate to histogram" lines wrap theme={null}
      LDObserve.recordHistogram(metric);
    ```

    ```js title="Record counter" lines wrap theme={null}
      // a counter metric may be incremented or decremented
      LDObserve.recordUpDownCounter(metric);
    ```
  </CodeGroup>

  To learn more, read [`Observe`](https://launchdarkly.github.io/observability-sdk/sdk/@launchdarkly/observability-node/interfaces/Observe.html).
</Accordion>

### Python

<Accordion title="Expand Python code sample">
  To record a metric, pass the name, value, and optional attributes to the appropriate `record_*` function. For example, you might want to record the value for a point-in-time measurement, such as the current CPU utilization percentage, or for a counter, such as the number of cache hits. The optional attributes may include any [attributes from the OpenTelemetry specification](https://opentelemetry.io/docs/specs/semconv/general/attributes/).

  Metrics with the same name and attributes are aggregated using the OpenTelemetry SDK. To learn more, read the OTel documentation on the [Metrics Data Model](https://opentelemetry.io/docs/specs/otel/metrics/data-model/).

  Here are the options for recording metrics:

  <CodeGroup>
    ```python title="Record point-in-time" lines wrap theme={null}
      observe.record_metric("example-metric-name", 3.7)
    ```

    ```python title="Record cumulative count" lines wrap theme={null}
      observe.record_count("example-metric-name", 42)
    ```

    ```python title="Record cumulative increment" lines wrap theme={null}
      observe.record_incr("example-metric-name")
    ```

    ```python title="Record point-in-time, aggregate to histogram" lines wrap theme={null}
      observe.record_histogram("example-metric-name", 3.7)
    ```

    ```python title="Record counter" lines wrap theme={null}
      # a counter metric may be incremented or decremented
      observe.record_up_down_counter("example-metric-name", 42);
    ```
  </CodeGroup>

  To learn more, read [`ldobserve`](https://launchdarkly.github.io/observability-sdk/sdk/@launchdarkly/observability-python/ldobserve.html).
</Accordion>
