Skip to content

feat(grafana): resolve curated pack fields per --field-profile - #431

Merged
shmsr merged 9 commits into
feat/grafana-741-8171-kubernetes-packsfrom
feat/grafana-field-profile-portability
Sep 2, 2026
Merged

feat(grafana): resolve curated pack fields per --field-profile#431
shmsr merged 9 commits into
feat/grafana-741-8171-kubernetes-packsfrom
feat/grafana-field-profile-portability

Conversation

@shmsr

@shmsr shmsr commented Sep 1, 2026

Copy link
Copy Markdown
Member

Summary

  • Packs author canonical names; SchemaResolver maps labels, metric_map targets, and control fields to the active --field-profile (otel, prometheus_native, prometheus_metrics, prometheus_remote_write, passthrough via source_label_names).
  • Profile-leakage linter plus a cross-profile corpus harness so native PROMQL stays byte-identical and other profiles do not leak labels.* / metrics.* / prometheus.* into the wrong layout.
  • Native PROMQL metric_map targets are namespaced through resolve_metric_field (bare pg_database_size_bytes became metrics.pg_database_size_bytes under prometheus_native).

Stacks on #430 (feat/grafana-741-8171-kubernetes-packs). Follow-up converts the 14 curated packs to canonical authoring.

Test plan

  • pytest tests/test_field_profile_portability.py
  • pytest tests/test_curated_packs.py (engine tests still green on this base)
  • make lint
  • Cross-profile corpus: 69 dashboards × 5 profiles, zero leakage; native vs pre-conversion goldens 68/69 identical (known Loki grouping nondeterminism)

Tracking: obs-integration-team #1201

@shmsr shmsr added source:grafana Grafana source migration asset:dashboards Dashboard migration assets program:grafana-engine Grafana translator and engine correctness labels Sep 1, 2026
@shmsr
shmsr force-pushed the feat/grafana-field-profile-portability branch from 64b1d88 to 173298b Compare September 2, 2026 08:25
@shmsr

shmsr commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

Rebased onto the restacked #430 tip (096d6951 on main). 8 unique commits, MERGEABLE vs #430.

Add an offline linter that flags ES|QL field spellings that don't match a
requested --field-profile (e.g. `labels.pod` under otel), which would be hard
`Unknown column` errors on a real target. Provides check_profile_leakage and
extract_esql_queries for later curated-pack portability tasks to import.
Plumb an optional source_label_names mapping (canonical label -> source
spelling) from the pack query block through the strict pydantic model onto
RulePackConfig, populated by the pack loader and merged from user overrides.
Pure plumbing; later tasks consume it to emit source-faithful label names
under --field-profile passthrough.
Make SchemaResolver.resolve_label field-profile aware. A label_rewrites
target that is itself a canonical label now recurses so profile
namespacing applies (Heapster pod_name -> pod -> per-profile spelling),
while a concrete non-canonical target is returned verbatim as a
documented escape hatch. Under the passthrough profile, resolution is
source-faithful via RulePackConfig.source_label_names. Output under
prometheus_native is unchanged (primary safety invariant).

Adds the _is_canonical_label helper and guards recursion with a
target != label + canonical check so at most one hop is taken.
resolve_metric_field previously returned an applied metric_map target
verbatim, forcing every shipped pack to author metrics.-prefixed targets.
An applied mapping now sets a bare logical_name that flows through the
existing profile-namespacing branches (native metrics.<t>, prometheus_metrics
prometheus.metrics.<t>, remote_write prometheus.<t>.<suffix>, otel bare <t>).

De-prefix all 6 shipped packs' metric_map targets in the same commit so
native emission stays byte-identical (net-zero for native), while otel and
the other profiles now get the correct spelling instead of a leaked metrics.
prefix. Adds a parametrized namespacing test plus a per-pack native-identity
guard, updates the raw-target curated-pack assertions, and refreshes the
metric_map docs (Grafana targets are bare logical names; Datadog stays
verbatim).
…acle

resolve_metric_field recorded the bare mapped.target in
_metric_map_applied, which migration_report.json surfaces and
obs-migrate compare replays single-hop into
parity_oracle.qualify_source_metric_names. A bare target under-qualified
the reference PromQL for a renamed metric (bare <t> instead of the
namespaced field the translated ES|QL uses, e.g. metrics.<t> under
prometheus_native), so the reference side matched nothing.

Record the fully-resolved, profile-namespaced field at each return point
via a local _emit helper instead of the bare target. Keeps the
logical_name = mapped.target flow unchanged; no recursion.
resolve_control_field now routes a canonical override value through
resolve_label so it namespaces per active field profile; concrete
override values remain a verbatim escape hatch and no-override cases
resolve the variable name as before. Native output is unchanged since
all shipped pack control_field_overrides values are concrete.
…harness

Guard the field-profile portability change with a golden test that asserts the
prometheus_native migration of the pinned 741/8171 Grafana fixtures stays
byte-identical to the pre-change baseline, plus a reusable harness script that
migrates a corpus under every field profile and gates on profile leakage,
feasibility parity vs prometheus_native, and optional native byte-identity.
The native PROMQL selector rewrite emitted the pack's bare metric_map
target (e.g. `sum(pg_database_size_bytes{...})`) after the targets were
de-prefixed for profile portability. A bare field addresses nothing in a
`metrics.*`-namespaced native index, so renamed-metric panels rendered
empty and prometheus_native output was no longer byte-identical to the
pre-portability engine.

Route the applied metric_map target back through resolve_metric_field so
it is namespaced for the active field profile (`metrics.<t>` under native,
`prometheus.metrics.<t>` under prometheus_metrics, bare under otel,
source-faithful under passthrough) exactly like a non-renamed metric.
Restores native byte-identity for all 69 corpus dashboards (solo).
The 8171 pack now emits time_bucket + labels.device instead of native
PROMQL GROK step; keep the byte-identical gate in lockstep.
@shmsr
shmsr force-pushed the feat/grafana-field-profile-portability branch from 173298b to cc86cd6 Compare September 2, 2026 11:36
@shmsr
shmsr merged commit 134491e into main Sep 2, 2026
14 checks passed
An error occurred while trying to automatically change base from feat/grafana-741-8171-kubernetes-packs to main September 2, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

asset:dashboards Dashboard migration assets program:grafana-engine Grafana translator and engine correctness source:grafana Grafana source migration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant