elastic / elastic/observability-migration-platform
Auto-legend PROMQL panels use the wrong series breakdown
- Dominant language
- Python
- Stars
- 6
- Forks
- 8
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 20
Description
## Summary
After migrating Grafana timeseries panels with `legendFormat: "__auto"`, the Kibana Lens panel sets **breakdown to `label`**, but the native PROMQL query never emits a `label` column.
Available fields are `value`, `step`, and `_timeseries`. Lens fails with:
`Provided column name or index is invalid: line_0_breakdown`
Grafana `__auto` means "derive series identity from labels". The migrated panel should break down on `_timeseries`, not a missing `label` field.
## Reproduction
```bash
obs-migrate migrate \
--source grafana \
--assets dashboards \
--input-mode files \
--input-dir /path/to/folder/with/dashboard.json \
--kibana-url "$KIBANA_URL" \
--kibana-api-key "$KIBANA_API_KEY" \
--es-url "$ES_URL" \
--es-api-key "$ES_API_KEY" \
--upload
```
Source Grafana dashboard JSON
```json
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 12,
"links": [],
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 0,
"y": 0
},
"id": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.6.0",
"targets": [
{
"editorMode": "code",
"expr": "node_disk_read_bytes_total",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Request total ",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 8,
"y": 0
},
"id": 1,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.6.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"editorMode": "code",
"expr": "rate(node_disk_read_bytes_total[$__rate_interval])",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Request rate (auto)",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 8,
"x": 16,
"y": 0
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "11.6.0",
"targets": [
{
"editorMode": "code",
"expr": "increase(node_disk_read_bytes_total[$__rate_interval])",
"legendFormat": "__auto",
"range": true,
"refId": "A"
}
],
"title": "Request increase (auto)",
"type": "timeseries"
}
],
"preload": false,
"schemaVersion": 41,
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Issue 2",
"uid": "efst5tc0vnpj4e",
"version": 6
}
```
### What we see after migration
Panels fail to render. Breakdown is set to `label`:
- Available fields in the query result: `# value`, `step`, `_timeseries`
- `label` is **not** in the result set
Example migrated query (raw counter panel):
```esql
PROMQL index=metrics-* start=?_tstart end=?_tend buckets=50 value=(node_disk_read_bytes_total)
```
Source Grafana panels all use `legendFormat: "__auto"` with:
- `node_disk_read_bytes_total`
- `rate(node_disk_read_bytes_total[$__rate_interval])`
- `increase(node_disk_read_bytes_total[$__rate_interval])`
## Acceptance criteria
1. **`legendFormat: "__auto"` must not invent a `label` breakdown.** Use `_timeseries` (or extract real label columns) so Lens has a valid series identity field.
2. **Empty `legendFormat` behavior stays unchanged** (issue #101 — single unlabeled series / no synthetic label pipe).
3. **Check in Kibana**
After re-migrate + upload, panels render without `line_0_breakdown` errors and show one series per `_timeseries` identity.
Contributor guide
Research direction
Start with the obs-migrate migrate entry point and reproduce the issue using the provided Grafana dashboard and upload command. Trace how legendFormat is converted into the Lens breakdown, then verify the migrated PROMQL panels use _timeseries for __auto while empty legendFormat behavior remains unchanged. Re-migrate and upload in Kibana to confirm the panels render without line_0_breakdown errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- observability, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100