Blog

Native OTLP metrics ingestion on Elastic Cloud Hosted

Send an exponential OpenTelemetry histogram and Elasticsearch keeps the scale and buckets you sent. All four type and temporality combinations work now, and your SDK and Collector config stay exactly as they are.

Elastic speaks OpenTelemetry natively. Send traces, logs, and metrics over OTLP straight into Elasticsearch, no proprietary agents required. See how it fits together, try it for free in the cloud, or run it locally.

Upgrade an Elastic Cloud Hosted (ECH) deployment to Elastic Stack 9.5.3 or later and Elasticsearch stores every OpenTelemetry histogram you send it. Cumulative histograms are included, and exponential buckets keep the scale and offset you sent, which covers all four combinations of histogram type and temporality. The Elastic Cloud Managed OTLP Endpoint picks the ingestion path per deployment, so nothing changes in your SDK or Collector config. Older deployments keep working through the Elasticsearch bulk API. Four runnable curl examples follow, one per histogram case.

What is the Elastic Cloud Managed OTLP Endpoint?

Managed inputs are ingestion frontends that Elastic operates on your behalf. You point a shipper at an Elastic-owned endpoint, authenticate with an API key, and Elastic takes care of receiving, buffering, and indexing the data into your deployment. There is no gateway to size, patch, or monitor, and no backend credentials to distribute to edge agents.

The Managed OTLP Endpoint is the managed input for OpenTelemetry data. It accepts standard OTLP over HTTP and gRPC from any OpenTelemetry SDK or Collector distribution, buffers it durably, and indexes it into your Elasticsearch deployment using the OpenTelemetry data model. It is generally available on both Elastic Cloud Serverless and ECH. For an overview across logs, traces, and metrics, read Now GA: Managed OTLP Endpoint on Elastic Cloud Hosted.

For metrics, clients send OTLP/HTTP requests to the /v1/metrics signal path and authenticate with an Elasticsearch API key that has the event:write privilege for the apm application:

POST https://<managed-otlp-endpoint>/v1/metrics
Authorization: ApiKey <encoded-api-key>

The /v1/metrics client-facing path never changes. This post focuses on what happens after the request is accepted, during the last hop between the managed pipeline and Elasticsearch.

Two ways to ingest OpenTelemetry metrics: the bulk API and the native OTLP endpoint

Elasticsearch offers two ways to receive OpenTelemetry metrics.

The bulk API (/_bulk) is the general-purpose document ingestion API. To use it for OTLP metrics, something upstream must convert each OTLP data point into a JSON document that follows the OpenTelemetry mapping mode, group the documents by target data stream, serialize them as newline-delimited JSON, and send them in bulk requests. In the OpenTelemetry Collector ecosystem, this conversion is handled by the Elasticsearch exporter, and until recently, it was the only option.

The native OTLP endpoint (/_otlp/v1/metrics) accepts OTLP/HTTP Protobuf directly. Elasticsearch decodes the payload, builds the documents itself, and indexes them into time series data streams. Because Elasticsearch sees the original OTLP structure, it can perform these steps directly:

  • It reads the aggregation temporality of every data point and stores it as a dimension
  • It hashes the shared resource attributes once for all data points in a resource
  • It maps exponential histograms to the exponential_histogram field type without an intermediate T-Digest conversion

The following diagram shows the two lanes.

The two paths differ in three ways that matter for users:

  • Work distribution. On the bulk path, the managed pipeline converts and serializes documents, then Elasticsearch parses them again. On the native path, the pipeline forwards batched Protobuf and Elasticsearch builds documents once.
  • Temporality. The Elasticsearch exporter used by the managed bulk path does not support cumulative histograms and drops those points. The native path preserves temporality and accepts both delta and cumulative histograms.
  • Histogram fidelity. The bulk path converts every histogram to a T-Digest style representation. The native path stores exponential histograms natively and converts explicit-boundary histograms into the same exponential representation.

Do not confuse the two paths with the client-facing path. Clients always send to /v1/metrics on the Managed OTLP Endpoint. The service chooses between /_bulk and /_otlp/v1/metrics behind it.

Native OpenTelemetry metrics support by Elastic Stack version

Native OTLP metrics support in Elasticsearch arrived in several steps.

  1. Elastic Stack 9.2 introduced the Elasticsearch OTLP/HTTP metrics endpoint as a technical preview.
  2. Elastic Stack 9.3 added the exponential_histogram field type as a technical preview.
  3. Elastic Stack 9.4 made exponential_histogram generally available and the default mapping for OTLP histograms received on the native endpoint.
  4. Elastic Stack 9.5 added metric temporality support as a generally available feature. The native endpoint now stores the temporality of every data point, which is what makes cumulative histograms possible. The same release added OTLP/HTTP endpoints for logs and traces as a technical preview.
  5. Elastic Stack 9.5.3 is the current minimum version for native OTLP metrics routing through the Managed OTLP Endpoint on ECH. The routing floor was raised from 9.2.0 because earlier versions can fail native OTLP requests when audit request-body logging processes Protobuf payloads. The 9.5.3 floor includes the required fixes.

The Elasticsearch Prometheus remote write endpoint arrived in Elastic Stack 9.4 and follows the same capability-gating model, but it is out of scope for this post.

Keep two things apart when reading version numbers in this post. The first four milestones are capabilities of Elasticsearch itself, available to anyone who calls /_otlp/v1/metrics directly. The fifth is a routing decision of the Managed OTLP Endpoint, which is stricter than "the endpoint exists" because the managed service has to work reliably for every tenant.

How Elastic Cloud Hosted routes OpenTelemetry metrics

On Serverless, Elastic operates and upgrades the backend, so the Managed OTLP Endpoint always uses the native path and users never see a version matrix.

ECH is different. Users pick and control their Elastic Stack version, and the Managed OTLP Endpoint supports deployments on any version from 9.0 onward. A single multi-tenant service therefore receives metrics for deployments that have no native endpoint at all, deployments that have one but predate the fixes the service relies on, and deployments that are fully ready. It cannot enable the native path unconditionally.

How the Managed OTLP Endpoint routes a metrics request

The following diagram shows what happens to a metrics request for an ECH deployment.

  1. The endpoint authenticates the API key and resolves the target ECH deployment.
  2. It looks up the deployment's Elasticsearch version from Elastic's own control plane, not from anything the client sends.
  3. It derives a small set of capability flags for the target, such as "native OTLP metrics supported", and attaches them to the request as metadata.
  4. The request is buffered durably together with its metadata.
  5. At the indexing stage, the consumer reads the flags and hands the batch to one of two exporters: the OTLP/HTTP exporter, which forwards Protobuf to /_otlp/v1/metrics, or the Elasticsearch exporter, which converts the batch into documents and posts them to /_bulk.

Because the flags are derived inside Elastic's trust boundary, a client cannot opt a deployment into a path its version does not support. Elastic can also pin specific deployments to the bulk API for compatibility reasons, so the version rule below describes the normal case rather than a guarantee.

Which ingestion path does my deployment use?

ECH Elastic Stack versionPath the Managed OTLP Endpoint normally uses
9.0 to 9.5.2Bulk API (/_bulk)
9.5.3 or laterNative OTLP endpoint (/_otlp/v1/metrics)

No client-side change is required. If you already send OTLP metrics to the Managed OTLP Endpoint on ECH, your traffic moves to the native path when you upgrade the deployment to 9.5.3 or later.

What changes when OpenTelemetry metrics move to the native path

Client configuration and data stream routing remain unchanged. Histogram representation and temporality handling change: the native path uses exponential_histogram by default and records temporality as a dimension. Review dashboards, alerts, and queries that depend on the previous histogram representation or aggregate cumulative snapshots. Queries spanning historical histogram fields and newer exponential_histogram fields may need an explicit ::exponential_histogram cast, as described in querying historical data alongside new data.

The distribution of work across the ingestion chain also changes. On the bulk path, the managed pipeline converts every data point into a JSON document, serializes it, and Elasticsearch parses that JSON back into a document and hashes the dimensions of each one to compute its time-series identifier. On the native path, Elasticsearch decodes a compact Protobuf payload once, and because it sees the OTLP resource and scope structure, it can hash the resource attributes once and reuse that partial hash for every data point that shares the resource, instead of re-hashing the full dimension set per document. The pull request that introduced the endpoint names both effects, the binary encoding and the reused partial hashes, as the reasons the native endpoint is more efficient than bulk ingestion of the same data.

There are also capabilities you gain compared with the Elasticsearch exporter currently used by the managed bulk path. The native endpoint records the aggregation temporality of each data point, stores histograms in the exponential_histogram field type, and accepts cumulative histograms. These are differences between the two managed ingestion implementations, not inherent restrictions of the Bulk API. Custom bulk clients can index exponential histogram documents and configure a temporality dimension. The rest of this post is about those differences.

OpenTelemetry histogram types and temporality explained

The most visible difference between the two paths is what happens to histograms, so the rest of this post is a tour through every histogram case.

OpenTelemetry defines two histogram data types. Histogram uses explicit bucket boundaries chosen by the producer. ExponentialHistogram uses exponentially spaced buckets controlled by a scale parameter, so the SDK adapts resolution to the data.

Each type can use one of two temporalities. With delta temporality, every data point covers one collection interval. With cumulative temporality, every data point covers everything since a fixed start time.

That gives four combinations, and the two ingestion paths treat them differently.

PathExplicit, deltaExplicit, cumulativeExponential, deltaExponential, cumulative
Bulk API (ECH 9.0 to 9.5.2)Supported, convertedDroppedSupported, convertedDropped
Native (ECH 9.5.3 or later)Supported, convertedSupported, convertedSupportedSupported

"Converted" means the metric is accepted but stored with a different bucket representation than the one on the wire. On the native path, that representation is the exponential_histogram field type, which is the default mapping for OTLP histograms since 9.4. Cumulative histograms on the native path require that default; if a cluster overrides xpack.otel_data.histogram_field_type to histogram, cumulative histograms are not supported. If Elastic has pinned a deployment to the bulk API for compatibility, the bulk row applies regardless of version.

Each of the four examples below is a complete curl request you can run against your own deployment. The JSON encoding of OTLP/HTTP is verbose but self-documenting, which makes it a good learning tool. Production shippers use Protobuf (application/x-protobuf) instead.

Prerequisites: your endpoint URL and API key

In the Elastic Cloud Console, find your deployment under Hosted deployments and select Manage. In Application endpoints, cluster and component IDs, select Managed OTLP and copy the public endpoint.

Then open the API keys management page in Kibana and create an API key with the event:write privilege for the apm application. Use the Encoded value of the key. It is already base64-encoded in the id:api_key format that the Authorization header expects.

export MANAGED_OTLP_URL="https://your-endpoint.elastic-cloud.com"
export ELASTIC_API_KEY="your-encoded-api-key"

# Nanosecond-precision timestamps: T0 = 2 min ago, T1 = 1 min ago, T2 = now
T0="$(python3 -c 'import time; print(time.time_ns() - 120_000_000_000)')"
T1="$(python3 -c 'import time; print(time.time_ns() -  60_000_000_000)')"
T2="$(python3 -c 'import time; print(time.time_ns())')"

All four examples report the same metric, http.server.request.duration in seconds, for the same service. Each has a distinct example.case resource attribute so the examples form separate time series and can be queried independently. The explicit and exponential examples describe different latency distributions; each cumulative example contains two snapshots whose difference matches its delta counterpart. Run the timestamp setup again before repeating the examples to avoid resending points with the same dimensions and timestamp.

Explicit histogram with delta temporality (case 1)

This is the case that works on every supported ECH version, so it is the right place to learn the shape of an OTLP histogram.

A histogram distributes individual measurements across buckets. For an explicit histogram, you choose the bucket boundaries in advance. For example: 5 ms, 10 ms, and 25 ms, and the SDK counts how many requests fell into each bucket. Each data point carries the bucket counts, the total count, and the sum, which is enough to estimate percentiles at query time.

Percentiles are what you want for latency. An average of 50 ms hides the fact that 1% of requests take 5 seconds, while a histogram shows p50, p95, and p99 side by side.

curl --fail-with-body --silent --show-error \
  -H "Authorization: ApiKey ${ELASTIC_API_KEY}" \
  -H "Content-Type: application/json" \
  --data-binary '{
    "resourceMetrics": [
      {
        "resource": {
          "attributes": [
            {"key": "service.name", "value": {"stringValue": "my-service"}},
            {"key": "example.case", "value": {"stringValue": "explicit-delta"}}
          ]
        },
        "scopeMetrics": [
          {
            "scope": {"name": "http"},
            "metrics": [
              {
                "name": "http.server.request.duration",
                "unit": "s",
                "histogram": {
                  "aggregationTemporality": 1,
                  "dataPoints": [
                    {
                      "startTimeUnixNano": "'"${T1}"'",
                      "timeUnixNano":      "'"${T2}"'",
                      "count": 100,
                      "sum": 12.5,
                      "explicitBounds": [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5],
                      "bucketCounts":   [2,     5,    10,    20,   30,  18,   10,  4,   1,  0],
                      "attributes": [
                        {"key": "http.request.method",       "value": {"stringValue": "GET"}},
                        {"key": "http.response.status_code", "value": {"intValue": 200}}
                      ]
                    }
                  ]
                }
              }
            ]
          }
        ]
      }
    ]
  }' \
  "${MANAGED_OTLP_URL}/v1/metrics"

aggregationTemporality: 1 means delta. The data point covers the one-minute window from startTimeUnixNano to timeUnixNano and nothing before it.

explicitBounds lists nine upper boundaries, so bucketCounts has ten entries. The last entry is the overflow bucket for values above 2.5 seconds.

A successful response is HTTP 200 with an empty or absent partialSuccess object, meaning the managed endpoint durably accepted the data for processing. It does not confirm that Elasticsearch indexed the points: unsupported cumulative histograms can still be dropped on the managed bulk path, and indexing can fail downstream. Use the queries below to verify ingestion. See indexing errors and the failure store for troubleshooting.

How Elastic stores it. Both paths accept this payload, and both convert it. On the bulk path, the Elasticsearch exporter turns the buckets into a T-Digest style histogram field. On the native path, Elasticsearch converts the explicit boundaries into an exponential_histogram. In both cases percentile precision is bounded by the boundaries you chose on the producer side, because the conversion cannot recover detail that the original buckets did not have.

Explicit histogram with cumulative temporality (case 2)

This case uses the same metric and bucket boundaries as case 1, with cumulative counts and a fixed start time. This is the case that separates the two paths most sharply.

Cumulative temporality is the default in most OpenTelemetry SDKs and the model Prometheus users know. Every data point reports the totals since the process started, so the counts only grow and a consumer computes the rate over a window by subtracting two points. It is resilient to lost data points, because the next point still carries the full state.

curl --fail-with-body --silent --show-error \
  -H "Authorization: ApiKey ${ELASTIC_API_KEY}" \
  -H "Content-Type: application/json" \
  --data-binary '{
    "resourceMetrics": [
      {
        "resource": {
          "attributes": [
            {"key": "service.name", "value": {"stringValue": "my-service"}},
            {"key": "example.case", "value": {"stringValue": "explicit-cumulative"}}
          ]
        },
        "scopeMetrics": [
          {
            "scope": {"name": "http"},
            "metrics": [
              {
                "name": "http.server.request.duration",
                "unit": "s",
                "histogram": {
                  "aggregationTemporality": 2,
                  "dataPoints": [
                    {
                      "startTimeUnixNano": "'"${T0}"'",
                      "timeUnixNano":      "'"${T1}"'",
                      "count": 150,
                      "sum": 18.5,
                      "explicitBounds": [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5],
                      "bucketCounts":   [3,     7,    15,    30,   45,  27,   15,  6,   2,  0],
                      "attributes": [
                        {"key": "http.request.method",       "value": {"stringValue": "GET"}},
                        {"key": "http.response.status_code", "value": {"intValue": 200}}
                      ]
                    },
                    {
                      "startTimeUnixNano": "'"${T0}"'",
                      "timeUnixNano":      "'"${T2}"'",
                      "count": 250,
                      "sum": 31.0,
                      "explicitBounds": [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5],
                      "bucketCounts":   [5,     12,   25,    50,   75,  45,   25,  10,  3,  0],
                      "attributes": [
                        {"key": "http.request.method",       "value": {"stringValue": "GET"}},
                        {"key": "http.response.status_code", "value": {"intValue": 200}}
                      ]
                    }
                  ]
                }
              }
            ]
          }
        ]
      }
    ]
  }' \
  "${MANAGED_OTLP_URL}/v1/metrics"

aggregationTemporality: 2 means cumulative. Both points retain T0 as the fixed start of the series. The first reports 150 requests through T1; the second reports 250 through T2. Subtracting their counts, sums, and corresponding buckets gives the 100-request distribution for T1 to T2 shown in case 1.

How Elastic stores it. On the native path Elasticsearch stores the point as an exponential_histogram and records cumulative in the temporality dimension. Time series functions in ES|QL use that dimension to compute per-interval rates from consecutive cumulative points.

On the bulk path this data point is dropped. The managed bulk path's Elasticsearch exporter does not support cumulative histograms; treating those buckets as delta would produce incorrect interval distributions. If your ECH deployment is on 9.0 to 9.5.2, configure your SDK or Collector to export histograms with delta temporality, or put a cumulativetodelta processor in front of the export.

Exponential histogram with delta temporality (case 3)

Now switch the data type while keeping delta temporality.

An exponential histogram removes the need to pick boundaries. Its buckets are exponentially spaced and controlled by a single scale parameter, and the SDK lowers the scale automatically when the data range grows. That is why exponential histograms are the recommended default for latency SLOs where p99 and p99.9 accuracy matters: the resolution is relative to the value, so the tail is captured as precisely as the body.

curl --fail-with-body --silent --show-error \
  -H "Authorization: ApiKey ${ELASTIC_API_KEY}" \
  -H "Content-Type: application/json" \
  --data-binary '{
    "resourceMetrics": [
      {
        "resource": {
          "attributes": [
            {"key": "service.name", "value": {"stringValue": "my-service"}},
            {"key": "example.case", "value": {"stringValue": "exponential-delta"}}
          ]
        },
        "scopeMetrics": [
          {
            "scope": {"name": "http"},
            "metrics": [
              {
                "name": "http.server.request.duration",
                "unit": "s",
                "exponentialHistogram": {
                  "aggregationTemporality": 1,
                  "dataPoints": [
                    {
                      "startTimeUnixNano": "'"${T1}"'",
                      "timeUnixNano":      "'"${T2}"'",
                      "count": 100,
                      "sum": 62.2,
                      "scale": 3,
                      "zeroCount": 0,
                      "positive": {
                        "offset": -10,
                        "bucketCounts": [2, 5, 10, 20, 30, 18, 10, 4, 1]
                      },
                      "attributes": [
                        {"key": "http.request.method",       "value": {"stringValue": "GET"}},
                        {"key": "http.response.status_code", "value": {"intValue": 200}}
                      ]
                    }
                  ]
                }
              }
            ]
          }
        ]
      }
    ]
  }' \
  "${MANAGED_OTLP_URL}/v1/metrics"

Reading the bucket layout takes a moment the first time.

The base of the histogram is 2^(2^-scale). With scale: 3 that is about 1.09, so each bucket is 9% wider than the previous one.

Bucket i in bucketCounts covers the range (base^(offset+i), base^(offset+i+1)], lower bound excluded and upper bound included. With offset: -10 the first bucket starts at about 0.42 seconds and the ninth ends at about 0.92 seconds.

zeroCount counts measurements that are exactly zero or within the zero threshold, and a negative bucket range exists for negative values, which latency never uses.

How Elastic stores it. On the native path Elasticsearch stores the scale, offset, and counts as an exponential_histogram without conversion. This is the highest-fidelity case: what you measured is what you query.

On the bulk path the Elasticsearch exporter converts the exponential buckets into a T-Digest style histogram. The data point is accepted and percentiles remain usable, but the original scale and bucket layout are not preserved.

Exponential histogram with cumulative temporality (case 4)

The last case combines the adaptive bucket layout of case 3 with the cumulative semantics of case 2. An SDK configured for exponential histogram aggregation and cumulative export temporality produces this shape. The OpenTelemetry SDK default aggregation for histogram instruments is explicit buckets, so selecting exponential aggregation is a separate configuration choice.

curl --fail-with-body --silent --show-error \
  -H "Authorization: ApiKey ${ELASTIC_API_KEY}" \
  -H "Content-Type: application/json" \
  --data-binary '{
    "resourceMetrics": [
      {
        "resource": {
          "attributes": [
            {"key": "service.name", "value": {"stringValue": "my-service"}},
            {"key": "example.case", "value": {"stringValue": "exponential-cumulative"}}
          ]
        },
        "scopeMetrics": [
          {
            "scope": {"name": "http"},
            "metrics": [
              {
                "name": "http.server.request.duration",
                "unit": "s",
                "exponentialHistogram": {
                  "aggregationTemporality": 2,
                  "dataPoints": [
                    {
                      "startTimeUnixNano": "'"${T0}"'",
                      "timeUnixNano":      "'"${T1}"'",
                      "count": 150,
                      "sum": 93.3,
                      "scale": 3,
                      "zeroCount": 0,
                      "positive": {
                        "offset": -10,
                        "bucketCounts": [3, 7, 15, 30, 45, 27, 15, 6, 2]
                      },
                      "attributes": [
                        {"key": "http.request.method",       "value": {"stringValue": "GET"}},
                        {"key": "http.response.status_code", "value": {"intValue": 200}}
                      ]
                    },
                    {
                      "startTimeUnixNano": "'"${T0}"'",
                      "timeUnixNano":      "'"${T2}"'",
                      "count": 250,
                      "sum": 155.5,
                      "scale": 3,
                      "zeroCount": 0,
                      "positive": {
                        "offset": -10,
                        "bucketCounts": [5, 12, 25, 50, 75, 45, 25, 10, 3]
                      },
                      "attributes": [
                        {"key": "http.request.method",       "value": {"stringValue": "GET"}},
                        {"key": "http.response.status_code", "value": {"intValue": 200}}
                      ]
                    }
                  ]
                }
              }
            ]
          }
        ]
      }
    ]
  }' \
  "${MANAGED_OTLP_URL}/v1/metrics"

How Elastic stores it. On the native path this is stored exactly like case 3, as an exponential_histogram, plus the cumulative temporality dimension. Elasticsearch can then downsample and compute rates over the series correctly. The two points share the same start time and bucket layout; their difference is the delta distribution in case 3.

On the bulk path the data point is dropped, for the same reason as case 2.

Requires Elastic Stack 9.5.3 or later on ECH. On ECH 9.0 to 9.5.2, cases 2 and 4 are dropped. Emit delta histograms until you upgrade.

Query OpenTelemetry histogram percentiles with ES|QL

Sending is only half of the showcase. Open Discover in Kibana, switch to ES|QL mode, and first confirm that the documents arrived:

FROM metrics-*.otel-*
| EVAL duration = metrics.http.server.request.duration::exponential_histogram
| WHERE service.name == "my-service" AND duration IS NOT NULL
| KEEP @timestamp, resource.attributes.example.case, metrics.http.server.request.duration, attributes.http.request.method
| SORT @timestamp DESC
| LIMIT 10

On a native-path deployment the histogram field shows the scale, the bucket indices, and the counts you sent. On a bulk-path deployment you see the converted values and counts arrays instead, which is the visible trace of the conversion.

Then ask the question the histogram was collected for, the request latency percentiles:

TS metrics-*.otel-*
| WHERE service.name == "my-service" AND @timestamp >= NOW() - 5 minutes
| STATS p50 = PERCENTILE(metrics.http.server.request.duration::exponential_histogram, 50),
        p95 = PERCENTILE(metrics.http.server.request.duration::exponential_histogram, 95),
        p99 = PERCENTILE(metrics.http.server.request.duration::exponential_histogram, 99)
    BY resource.attributes.example.case, attributes.http.request.method, TBUCKET(5 minutes)

TS merges histograms per time series and respects their temporality before computing percentiles. For cumulative series, it accounts for the change between consecutive snapshots instead of counting their overlapping observations repeatedly. FROM is useful for inspecting individual documents, but it ignores temporality when aggregating them. See how temporality affects queries.

Grouping by resource.attributes.example.case keeps the four examples separate. The explicit examples place the median in the 0.05 to 0.1 second bucket; the exponential examples place it around 0.6 seconds. These are different input distributions, so their percentile results should differ. The cumulative examples describe the same final one-minute distribution as their corresponding delta examples. Refer to the ES|QL aggregation functions reference for the full list of functions that accept exponential histogram fields.

Summary: OpenTelemetry histogram support on Elastic Cloud Hosted

  • ECH deployments on Elastic Stack 9.5.3 or later receive OTLP metrics through the native Elasticsearch endpoint, with no client change.
  • Those deployments accept all four histogram cases, and exponential histograms are stored without conversion.
  • ECH deployments on 9.0 to 9.5.2 continue through the bulk API and should emit delta histograms.
  • Serverless deployments always use the native path.

Clients keep sending to the same /v1/metrics path on the Managed OTLP Endpoint in every case.

Learn more about OpenTelemetry metrics on Elastic

How helpful was this content?

Related Content

AI root cause analysis in Elastic Agent Builder that cites its evidence

AI root cause analysis in Elastic Agent Builder that cites its evidence

Jeffrey Rengifo
Drain Vercel into Elastic: serverless observability with nothing to install

Drain Vercel into Elastic: serverless observability with nothing to install

Ishleen Kaur
LLM tracing in Elastic APM: prompts, responses, and token counts in the span view

LLM tracing in Elastic APM: prompts, responses, and token counts in the span view

Jenny Pavlova
Your AI agent needs an alibi: Observability and audit trails for Agent Builder in Elastic

Your AI agent needs an alibi: Observability and audit trails for Agent Builder in Elastic

Jeffrey Rengifo
AI agent observability for Microsoft Foundry: two env vars, no collector

AI agent observability for Microsoft Foundry: two env vars, no collector

Greg Crist