Skip to content

fix(grafana): resolve multi-target legend collisions and aggregation-scope mismatches (#354, #355) - #364

Open
giorgi-imerlishvili-elastic wants to merge 1 commit into
elastic:mainfrom
giorgi-imerlishvili-elastic:fix/multi-target-legend-and-aggregation-scope
Open

fix(grafana): resolve multi-target legend collisions and aggregation-scope mismatches (#354, #355)#364
giorgi-imerlishvili-elastic wants to merge 1 commit into
elastic:mainfrom
giorgi-imerlishvili-elastic:fix/multi-target-legend-and-aggregation-scope

Conversation

@giorgi-imerlishvili-elastic

Copy link
Copy Markdown
Collaborator

Summary

Fixes two Grafana translator issues where fused multi-target XY panels silently changed panel semantics instead of degrading gracefully:

  • Multi-target panels label every series with the first target's legendFormat #354 — Multi-target legend collisions. When fused targets carried different multi-placeholder legendFormat templates, the composite EVAL legend expression mislabelled every series with the first target's literal text. The composite legend is now suppressed in that case so the STATS column name carries series identity instead; targets whose templates agree, or that use only a single placeholder, are unaffected.
  • PromQL aggregations without by are grouped per-series, so Min/Avg/Max become per-series duplicates #355 — Aggregation-scope mismatch. A bare aggregation (no by(), e.g. min/avg/max/sum) sharing its metric field with a grouped sibling target (the disk-graphs "IO Wait per core" Min/Avg/Max-over-CPUs shape) was union-grouped into the sibling's BY fields, turning a single cross-series line into per-group duplicates. It now renders as two separate ES|QL layers — reusing the existing cross-index-layer XY shape — so the bare aggregate is computed across every series, matching what Grafana always draws.

Additional refinements found and fixed during code review:

  • A bare target broadcasting an unrelated metric alongside a grouped breakdown (e.g. QoS by (qos_class) + an ungrouped fleet-wide total) no longer disables the split for a different, same-metric bare/grouped pair sharing the same panel — the warning now also names the changed semantics for the unrelated case instead of only describing the mechanism.
  • The bare/grouped split now applies inside each index partition of a cross-index panel, instead of being bypassed when other fused targets land on a different data stream.
  • A lone bare target's own static legendFormat text is preserved as its layer's column alias (instead of falling back to the raw metric field name), and no longer leaks onto the grouped layer's identity when the bare target happens to be listed first among the fused targets.

docs/sources/grafana.md is updated to describe the new legend-suppression and layer-split behavior, including the unrelated-bare-target and cross-index-partition cases.

Test plan

  • make test — 5749 passed, 3 skipped
  • make lint — clean
  • make typecheck — clean
  • New unit/integration tests: tests/test_grafana_issues_354_355.py (legend suppression, aggregation-scope split, unrelated-bare-target handling, order-independence, singleton bare-layer legend), plus a cross-index regression in tests/core/metric_mapping/test_cross_index_xy_layers.py and an updated warning-message assertion in tests/test_grafana_qos_union_by.py.
  • Visually verified against real Grafana dashboard 9852 ("node-exporter disk graphs") migrated end-to-end with live ES schema discovery, uploaded to a local Kibana, and seeded with synthetic telemetry: "IO Wait per core" now renders per-core series plus separate Min/Avg/Max layers, and "Disk IO" shows distinct composite legend labels per device.

…scope mismatches (elastic#354, elastic#355)

Fused multi-target XY panels previously mislabelled every series with the
first target's literal legendFormat text when templates disagreed (issue
elastic#354), and union-grouped a bare aggregation (no `by()`) into a grouped
sibling's BY fields instead of reproducing Grafana's single cross-series
line (issue elastic#355). Both silently changed panel semantics rather than
degrading gracefully with a warning.

- Suppress the composite legend expression when fused targets carry
  different multi-placeholder legendFormat templates, so the STATS column
  name carries series identity instead.
- Split a same-metric bare/grouped pair into two ES|QL layers (reusing the
  cross-index-layer XY shape) so the bare aggregate is computed across
  every series instead of per-group; keeps today's union behavior for
  bare targets that broadcast an unrelated metric, and applies the split
  inside each index partition of a cross-index panel.
- Preserve a lone bare target's own static legend text as its layer's
  column alias, and prevent that legend from leaking onto the grouped
  layer's identity when the bare target is listed first.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant