Commit b87e282
# Backport
This will backport the following commits from `main` to `9.5`:
- [[APM] Omit HDR percentiles when duration histogram is
exponential_histogram
(#290874)](#290874)
<!--- Backport version: 9.6.6 -->
### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)
<!--BACKPORT
[{"author":{"name":"Miriam","email":"31922082+MiriamAparicio@users.noreply.github.com"},"sourceCommit":{"committedDate":"2026-09-15T08:15:29Z","message":"[APM]
Omit HDR percentiles when duration histogram is exponential_histogram
(#290874)\n\n## Summary\n\n- Fixes Latency Distribution going blank or
500ing on OTel/mOTLP\nmetrics, where `transaction.duration.histogram` is
mapped as\n`exponential_histogram` and Elasticsearch rejects HDR
(`Percentiles\nalgorithm hdr must not be used with exponential_histogram
field`).\n- Before aggregating, field caps checks whether any metric
index maps\nthat field as `exponential_histogram` (including empty
mappings: HDR\nfails on mapping even with 0 hits). If so, HDR is
omitted; classic\n`histogram`-only clusters still use HDR.\n- Closes
#289525\n\n## Test plan\n\n### Unit\n\n- [ ] `node
scripts/jest\nx-pack/solutions/observability/plugins/apm/server/routes/correlations/queries/fetch_duration_percentiles.test.ts`\n-
[ ] `node
scripts/jest\nx-pack/solutions/observability/plugins/apm/server/routes/correlations/queries/has_exponential_histogram_mapping.test.ts`\n\n###
Manual: synthtrace + exponential_histogram stub\n\n`otel_simple_trace`
writes traces (and some OTel metrics) but **not**\nECS
`transaction.duration.histogram` as `exponential_histogram`. The\nextra
Dev Tools steps below are required to hit the bug path.\n\n1. Start the
stack (`yarn es snapshot` / `yarn start`, or your usual\nlocal
ES+Kibana).\n2. Ingest OTel traces (gives a service/transaction to open
in APM; other\nlatency charts should already have data):\n\n
```bash\nnode scripts/synthtrace otel_simple_trace --local --from=now-1h
--to=now\n ```\n\n3. In Console, create a high-priority template so
`metrics-repro.otel-*`\nis not swallowed by `metrics-otel@template`,
then recreate the data\nstream:\n\n ```json\n PUT
/_index_template/repro-exp-histo\n {\n \"index_patterns\":
[\"metrics-repro.otel-*\"],\n \"priority\": 1000,\n \"data_stream\":
{},\n \"template\": {\n \"mappings\": {\n \"properties\": {\n
\"@timestamp\": { \"type\": \"date\" },\n \"processor.event\": {
\"type\": \"keyword\" },\n \"service.name\": { \"type\": \"keyword\"
},\n \"service.environment\": { \"type\": \"keyword\" },\n
\"transaction.name\": { \"type\": \"keyword\" },\n \"transaction.type\":
{ \"type\": \"keyword\" },\n\"transaction.duration.histogram\": {
\"type\": \"exponential_histogram\" }\n }\n }\n }\n }\n\n DELETE
/_data_stream/metrics-repro.otel-default\n PUT
/_data_stream/metrics-repro.otel-default\n ```\n\n4. Index a metric doc
**inside the APM time picker** (Last 15 minutes /\nLast 1 hour). Use a
UTC timestamp a few minutes ago, not a future
time.\n`service.environment` must be keyword and match the
synthtrace\nenvironment:\n\n ```json\n POST
/metrics-repro.otel-default/_doc?refresh=true\n {\n \"@timestamp\":
\"<UTC now minus a few minutes>\",\n \"processor.event\": \"metric\",\n
\"service.name\": \"sendotlp-otel-native-synth\",\n
\"service.environment\": \"Synthtrace: otel_simple_trace\",\n
\"transaction.name\": \"oteldemo.AdServiceSynth/GetAds\",\n
\"transaction.type\": \"request\",\n \"transaction.duration.histogram\":
{\n \"scale\": 0,\n \"sum\": 1000,\n \"min\": 100,\n \"max\": 2000,\n
\"zero\": { \"count\": 0 },\n \"positive\": { \"indices\": [10],
\"counts\": [5] }\n }\n }\n ```\n\n5. In APM: **Traces** → service
`sendotlp-otel-native-synth` →\ntransaction
`oteldemo.AdServiceSynth/GetAds` → **Latency Distribution**\n(same time
range as the stub). Environment: `Synthtrace:\notel_simple_trace` or
All.\n\n6. **Before this PR:** chart is empty or toasts `An error
occurred\nfetching the overall latency distribution.`
Inspect\n`get_duration_percentiles` has `hdr` and may show shard
failures.\n\n7. **After this PR:**\n- Chart shows distribution bars (the
failed-transactions overlay can\nstill be empty; the stub has no
`event.outcome: failure`).\n- Inspect `get_duration_field_caps` returns
`exponential_histogram` for\n`transaction.duration.histogram`.\n-
Inspect `get_duration_percentiles` has `\"percentiles\": {
\"field\":\n\"transaction.duration.histogram\" }` **without** `hdr`,
`hits.total >=\n1`, numeric `95.0`.\n- Follow-up requests
`get_duration_histogram_range_steps` and\n`get_duration_ranges`
run.\n\n8. Optional classic check: without the stub (or on an
Elastic-agent\nsynthtrace scenario that only has `histogram` mappings),
Inspect should\nstill send `hdr` on
`transaction.duration.histogram`.","sha":"6a558186d8d1f94af0dec60adf987a9d88f0c340","branchLabelMapping":{"^v9.6.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport:version","v9.4.0","v9.5.0","v9.6.0","Team:obs-signals-traces"],"title":"[APM]
Omit HDR percentiles when duration histogram is
exponential_histogram","number":290874,"url":"https://github.com/elastic/kibana/pull/290874","mergeCommit":{"message":"[APM]
Omit HDR percentiles when duration histogram is exponential_histogram
(#290874)\n\n## Summary\n\n- Fixes Latency Distribution going blank or
500ing on OTel/mOTLP\nmetrics, where `transaction.duration.histogram` is
mapped as\n`exponential_histogram` and Elasticsearch rejects HDR
(`Percentiles\nalgorithm hdr must not be used with exponential_histogram
field`).\n- Before aggregating, field caps checks whether any metric
index maps\nthat field as `exponential_histogram` (including empty
mappings: HDR\nfails on mapping even with 0 hits). If so, HDR is
omitted; classic\n`histogram`-only clusters still use HDR.\n- Closes
#289525\n\n## Test plan\n\n### Unit\n\n- [ ] `node
scripts/jest\nx-pack/solutions/observability/plugins/apm/server/routes/correlations/queries/fetch_duration_percentiles.test.ts`\n-
[ ] `node
scripts/jest\nx-pack/solutions/observability/plugins/apm/server/routes/correlations/queries/has_exponential_histogram_mapping.test.ts`\n\n###
Manual: synthtrace + exponential_histogram stub\n\n`otel_simple_trace`
writes traces (and some OTel metrics) but **not**\nECS
`transaction.duration.histogram` as `exponential_histogram`. The\nextra
Dev Tools steps below are required to hit the bug path.\n\n1. Start the
stack (`yarn es snapshot` / `yarn start`, or your usual\nlocal
ES+Kibana).\n2. Ingest OTel traces (gives a service/transaction to open
in APM; other\nlatency charts should already have data):\n\n
```bash\nnode scripts/synthtrace otel_simple_trace --local --from=now-1h
--to=now\n ```\n\n3. In Console, create a high-priority template so
`metrics-repro.otel-*`\nis not swallowed by `metrics-otel@template`,
then recreate the data\nstream:\n\n ```json\n PUT
/_index_template/repro-exp-histo\n {\n \"index_patterns\":
[\"metrics-repro.otel-*\"],\n \"priority\": 1000,\n \"data_stream\":
{},\n \"template\": {\n \"mappings\": {\n \"properties\": {\n
\"@timestamp\": { \"type\": \"date\" },\n \"processor.event\": {
\"type\": \"keyword\" },\n \"service.name\": { \"type\": \"keyword\"
},\n \"service.environment\": { \"type\": \"keyword\" },\n
\"transaction.name\": { \"type\": \"keyword\" },\n \"transaction.type\":
{ \"type\": \"keyword\" },\n\"transaction.duration.histogram\": {
\"type\": \"exponential_histogram\" }\n }\n }\n }\n }\n\n DELETE
/_data_stream/metrics-repro.otel-default\n PUT
/_data_stream/metrics-repro.otel-default\n ```\n\n4. Index a metric doc
**inside the APM time picker** (Last 15 minutes /\nLast 1 hour). Use a
UTC timestamp a few minutes ago, not a future
time.\n`service.environment` must be keyword and match the
synthtrace\nenvironment:\n\n ```json\n POST
/metrics-repro.otel-default/_doc?refresh=true\n {\n \"@timestamp\":
\"<UTC now minus a few minutes>\",\n \"processor.event\": \"metric\",\n
\"service.name\": \"sendotlp-otel-native-synth\",\n
\"service.environment\": \"Synthtrace: otel_simple_trace\",\n
\"transaction.name\": \"oteldemo.AdServiceSynth/GetAds\",\n
\"transaction.type\": \"request\",\n \"transaction.duration.histogram\":
{\n \"scale\": 0,\n \"sum\": 1000,\n \"min\": 100,\n \"max\": 2000,\n
\"zero\": { \"count\": 0 },\n \"positive\": { \"indices\": [10],
\"counts\": [5] }\n }\n }\n ```\n\n5. In APM: **Traces** → service
`sendotlp-otel-native-synth` →\ntransaction
`oteldemo.AdServiceSynth/GetAds` → **Latency Distribution**\n(same time
range as the stub). Environment: `Synthtrace:\notel_simple_trace` or
All.\n\n6. **Before this PR:** chart is empty or toasts `An error
occurred\nfetching the overall latency distribution.`
Inspect\n`get_duration_percentiles` has `hdr` and may show shard
failures.\n\n7. **After this PR:**\n- Chart shows distribution bars (the
failed-transactions overlay can\nstill be empty; the stub has no
`event.outcome: failure`).\n- Inspect `get_duration_field_caps` returns
`exponential_histogram` for\n`transaction.duration.histogram`.\n-
Inspect `get_duration_percentiles` has `\"percentiles\": {
\"field\":\n\"transaction.duration.histogram\" }` **without** `hdr`,
`hits.total >=\n1`, numeric `95.0`.\n- Follow-up requests
`get_duration_histogram_range_steps` and\n`get_duration_ranges`
run.\n\n8. Optional classic check: without the stub (or on an
Elastic-agent\nsynthtrace scenario that only has `histogram` mappings),
Inspect should\nstill send `hdr` on
`transaction.duration.histogram`.","sha":"6a558186d8d1f94af0dec60adf987a9d88f0c340"}},"sourceBranch":"main","suggestedTargetBranches":["9.4","9.5"],"targetPullRequestStates":[{"branch":"9.4","label":"v9.4.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.5","label":"v9.5.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.6.0","branchLabelMappingKey":"^v9.6.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/290874","number":290874,"mergeCommit":{"message":"[APM]
Omit HDR percentiles when duration histogram is exponential_histogram
(#290874)\n\n## Summary\n\n- Fixes Latency Distribution going blank or
500ing on OTel/mOTLP\nmetrics, where `transaction.duration.histogram` is
mapped as\n`exponential_histogram` and Elasticsearch rejects HDR
(`Percentiles\nalgorithm hdr must not be used with exponential_histogram
field`).\n- Before aggregating, field caps checks whether any metric
index maps\nthat field as `exponential_histogram` (including empty
mappings: HDR\nfails on mapping even with 0 hits). If so, HDR is
omitted; classic\n`histogram`-only clusters still use HDR.\n- Closes
#289525\n\n## Test plan\n\n### Unit\n\n- [ ] `node
scripts/jest\nx-pack/solutions/observability/plugins/apm/server/routes/correlations/queries/fetch_duration_percentiles.test.ts`\n-
[ ] `node
scripts/jest\nx-pack/solutions/observability/plugins/apm/server/routes/correlations/queries/has_exponential_histogram_mapping.test.ts`\n\n###
Manual: synthtrace + exponential_histogram stub\n\n`otel_simple_trace`
writes traces (and some OTel metrics) but **not**\nECS
`transaction.duration.histogram` as `exponential_histogram`. The\nextra
Dev Tools steps below are required to hit the bug path.\n\n1. Start the
stack (`yarn es snapshot` / `yarn start`, or your usual\nlocal
ES+Kibana).\n2. Ingest OTel traces (gives a service/transaction to open
in APM; other\nlatency charts should already have data):\n\n
```bash\nnode scripts/synthtrace otel_simple_trace --local --from=now-1h
--to=now\n ```\n\n3. In Console, create a high-priority template so
`metrics-repro.otel-*`\nis not swallowed by `metrics-otel@template`,
then recreate the data\nstream:\n\n ```json\n PUT
/_index_template/repro-exp-histo\n {\n \"index_patterns\":
[\"metrics-repro.otel-*\"],\n \"priority\": 1000,\n \"data_stream\":
{},\n \"template\": {\n \"mappings\": {\n \"properties\": {\n
\"@timestamp\": { \"type\": \"date\" },\n \"processor.event\": {
\"type\": \"keyword\" },\n \"service.name\": { \"type\": \"keyword\"
},\n \"service.environment\": { \"type\": \"keyword\" },\n
\"transaction.name\": { \"type\": \"keyword\" },\n \"transaction.type\":
{ \"type\": \"keyword\" },\n\"transaction.duration.histogram\": {
\"type\": \"exponential_histogram\" }\n }\n }\n }\n }\n\n DELETE
/_data_stream/metrics-repro.otel-default\n PUT
/_data_stream/metrics-repro.otel-default\n ```\n\n4. Index a metric doc
**inside the APM time picker** (Last 15 minutes /\nLast 1 hour). Use a
UTC timestamp a few minutes ago, not a future
time.\n`service.environment` must be keyword and match the
synthtrace\nenvironment:\n\n ```json\n POST
/metrics-repro.otel-default/_doc?refresh=true\n {\n \"@timestamp\":
\"<UTC now minus a few minutes>\",\n \"processor.event\": \"metric\",\n
\"service.name\": \"sendotlp-otel-native-synth\",\n
\"service.environment\": \"Synthtrace: otel_simple_trace\",\n
\"transaction.name\": \"oteldemo.AdServiceSynth/GetAds\",\n
\"transaction.type\": \"request\",\n \"transaction.duration.histogram\":
{\n \"scale\": 0,\n \"sum\": 1000,\n \"min\": 100,\n \"max\": 2000,\n
\"zero\": { \"count\": 0 },\n \"positive\": { \"indices\": [10],
\"counts\": [5] }\n }\n }\n ```\n\n5. In APM: **Traces** → service
`sendotlp-otel-native-synth` →\ntransaction
`oteldemo.AdServiceSynth/GetAds` → **Latency Distribution**\n(same time
range as the stub). Environment: `Synthtrace:\notel_simple_trace` or
All.\n\n6. **Before this PR:** chart is empty or toasts `An error
occurred\nfetching the overall latency distribution.`
Inspect\n`get_duration_percentiles` has `hdr` and may show shard
failures.\n\n7. **After this PR:**\n- Chart shows distribution bars (the
failed-transactions overlay can\nstill be empty; the stub has no
`event.outcome: failure`).\n- Inspect `get_duration_field_caps` returns
`exponential_histogram` for\n`transaction.duration.histogram`.\n-
Inspect `get_duration_percentiles` has `\"percentiles\": {
\"field\":\n\"transaction.duration.histogram\" }` **without** `hdr`,
`hits.total >=\n1`, numeric `95.0`.\n- Follow-up requests
`get_duration_histogram_range_steps` and\n`get_duration_ranges`
run.\n\n8. Optional classic check: without the stub (or on an
Elastic-agent\nsynthtrace scenario that only has `histogram` mappings),
Inspect should\nstill send `hdr` on
`transaction.duration.histogram`.","sha":"6a558186d8d1f94af0dec60adf987a9d88f0c340"}}]}]
BACKPORT-->
Co-authored-by: Miriam <31922082+MiriamAparicio@users.noreply.github.com>
1 parent c1d05cf commit b87e282
4 files changed
Lines changed: 274 additions & 3 deletions
File tree
- x-pack/solutions/observability/plugins/apm/server/routes/correlations/queries
Lines changed: 147 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
Lines changed: 17 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| |||
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
| |||
62 | 64 | | |
63 | 65 | | |
64 | 66 | | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
65 | 75 | | |
66 | 76 | | |
67 | 77 | | |
| |||
76 | 86 | | |
77 | 87 | | |
78 | 88 | | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | 89 | | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
83 | 97 | | |
84 | 98 | | |
85 | 99 | | |
| |||
Lines changed: 74 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
Lines changed: 36 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
0 commit comments