fix: fail Grafana namespaced metric_map targets and cover field-profile ingest - #439
Conversation
…le ingest Offline Grafana runs already emit named Prometheus layouts, but the discovery warning still claimed every non-passthrough profile fell back to OTel service.name. Metric_map targets that already include the active profile prefix now fail closed instead of emitting metrics.metrics.*. Always-on ingest-story tests pin Grafana and Datadog field-profile emit.
Auto profile resolution ran inside schema discovery's broad exception path, turning prefix-lint failures into warnings and allowing invalid artifacts. Propagate only the dedicated lint error while preserving graceful discovery failures, and make the profile portability assertions non-vacuous.
The code-quality review flagged mixed parent and from-import forms. Import the mock submodule explicitly so TestCase and mock remain available through one consistent namespace without relying on unittest to load mock implicitly.
giorgi-imerlishvili-elastic
left a comment
There was a problem hiding this comment.
Verdict: fixed, then approved.
Review contract and paths exercised:
- Compared merge base
0a5340ad64b43764d74d8ae3a64fe22a8bb23a56through original heade34578c52ac5c40902b72cd716b7116a9d121367, then re-reviewed fixesd0dcf02a3487ba84bc356661b6a6e30fff045c62andfab56248f0f79f9244e20877684947ccfb8c2c69. - Exercised helper, resolver, and CLI paths for all three prefixed Grafana profiles; root/variant/empty/multiple map entries; explicit OTel/passthrough preservation;
autonamed-layout detection and OTel fallback; request/JSON error paths; profile-specific offline warning copy; Grafana/Datadog portability; docs and repository conventions. - Confirmed no panel/widget type or baseline changes. The only external review comment was evaluated and resolved below.
Findings and fixes:
- Important —
<observability_migration/adapters/source/grafana/schema.py:291-307>:_discover_fields()swallowed the new lint whenautoresolved to a named Prometheus layout, turning a required hard failure into a discovery warning and allowing invalid output. Ind0dcf02,<observability_migration/adapters/source/grafana/metric_map_lint.py:26-59>now raises a dedicatedGrafanaMetricMapPrefixError, and discovery re-raises only that signal while retaining graceful handling for unrelated request/JSON errors. Regression coverage is at<tests/core/metric_mapping/test_grafana_metric_map_prefix_lint.py:189-249>and<tests/core/metric_mapping/test_grafana_metric_map_prefix_lint.py:327-396>. - Minor —
<tests/test_grafana_field_profile_portability.py:197-210>and<tests/test_datadog_field_profile_portability.py:223-236>: distinct-query tests used different indexes per profile, so they passed even if every migration used OTel.d0dcf02makes all runs share_INDEX; mutation probes now fail when the profile argument is ignored. - Minor —
<docs/command-contract.md:597-609>: offline documentation incorrectly includedauto, although the CLI requires--es-url.d0dcf02now states that requirement and exit behavior. - Minor —
<tests/test_field_profile_portability.py:840-846>:d0dcf02removed the extra EOF blank line;git diff --checkis clean. - Minor/code-quality —
<tests/core/metric_mapping/test_grafana_metric_map_prefix_lint.py:9-13>mixedimport unittestandfrom unittest import mock.fab5624uses explicitimport unittest.mockandunittest.mock.*throughout. I verified the bot's literalimport unittest-only recipe would raiseAttributeErrorbecause it does not load the mock submodule, so the explicit submodule import preserves behavior while satisfying the single-style requirement. Replied in the original thread with the rationale and gates.
Artifact evidence: an identical mocked auto/native-caps control on original head exited 0 and wrote one native artifact containing metrics.metrics.already_prefixed; fixed head exits 1, writes zero native artifacts, and emits the logical-name guidance. This is a pre-translation CLI error path; valid-input dashboard output is unchanged. Kibana visual verification therefore does not apply—there is no fixed-path dashboard to upload or render.
Gate evidence on the fixes:
- Full targeted PR set after
d0dcf02: 128 passed, 58 skipped; import-style target afterfab5624: 21 passed. - Final
make test: 6,289 passed, 61 skipped, 473 subtests passed. - Final
make lint: exit 0; source headers 505/505 and Ruff clean. - Final
make typecheck: exit 0; mypy found 0 issues in 10 files. - Final manual configured pre-commit run: 5/5 hooks passed (Gitleaks, headers, Ruff, quick pytest, local-path check).
- Final pushed-head CI: 14/14 checks passed, including Python 3.11/3.12/3.13 pytest, E2E, Ruff, mypy, Gitleaks, packaging/CLI/clean-install smoke, CodeQL, CLA, and dependency/SBOM.
Concerns probed and found unfounded: auto→OTel still allows namespaced targets; unrelated request and JSON failures still degrade gracefully; explicit OTel/passthrough behavior and Datadog verbatim mapping remain unchanged. Original-head/base checks had no pre-existing failures. Remaining optional Minors: none.
Summary
metric_maptarget already carries the active Prometheus profile prefix (metrics.*,prometheus.metrics.*,prometheus.*), so operators get a logical-name hint instead ofmetrics.metrics.*in emitted ES|QL.otel/passthroughare unchanged; Datadog map files stay verbatim.--field-profilelayout (named Prometheus profiles no longer claim an OTelservice.namefallback).Test plan
pytest tests/core/metric_mapping/test_grafana_metric_map_prefix_lint.py— helper, resolver, CLI exit 1, shipped pack ratchetpytest tests/core/reporting/test_print_report.py— profile-specific offline warning copypytest tests/test_grafana_field_profile_portability.py tests/test_datadog_field_profile_portability.pypytest tests/test_command_contract_metric_map_examples.pygrafana-migrate --field-profile prometheus_native --metric-map-filewith ametrics.footarget and check stderrERROR:+ exit 1