Add stats-to-mapping CLI for regenerating upstream apm-server field mappings#20999
Closed
carsonip wants to merge 5 commits intoelastic:mainfrom
Closed
Add stats-to-mapping CLI for regenerating upstream apm-server field mappings#20999carsonip wants to merge 5 commits intoelastic:mainfrom
carsonip wants to merge 5 commits intoelastic:mainfrom
Conversation
Reads APM Server /stats JSON from stdin and updates the upstream Elasticsearch monitoring templates, Metricbeat fields.yml files, and the elastic_agent integration package in-place to expose those fields. Replaces the Python script proposed in elastic#13638 with a Go equivalent that produces byte-identical output, removing the ruamel.yaml setup step from the developer workflow. Tests are golden-file based and pin upstream snapshots of the five target files; outputs were generated once with the upstream Python script (with a seek(0) writeback fix) and committed alongside the inputs. No Python or shell regen scripts live in the repo — see cmd/stats-to-mapping/README.md for the regen procedure. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
JSON output now follows the same byte-splicing model already used for YAML:
read the file, find the byte range of the modified member's value with a
small JSON-aware byte navigator, replace it with a fresh JSON encoding of
the new subtree. The parent object's other children stay in their on-disk
order because we only swap values, never reorder the parent.
The replacement subtree is built from a plain map[string]any and emitted
via stdlib json.MarshalIndent, which sorts keys alphabetically — fine here
because the apm-server / output subtrees are already alphabetical at every
level in both the stats input and the existing target files. The one
behavioral change: alias entries now emit as
{"path": "...", "type": "alias"} rather than insertion-order
{"type": ..., "path": ...} — semantically identical, regenerated golden.
Net: -189 LOC for the deleted orderedMap module, plus modest trims in
convert.go (drops UseNumber / json.Number; sorted iteration via a
sortedKeys helper) and main_test.go (drops the diagnostic helpers in
favor of just printing the actual-output path on failure). Total moves
1182 -> 1038 LOC, no new deps.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
apm-server changed its /stats endpoint shape in elastic#15094 (Jan 2025): output metrics moved from a top-level "output" key to "libbeat.output", string scalars like "libbeat.output.type" appeared. EA also split "beat-fields.yml" into a separate "beat-stats-fields.yml" (elastic/integrations#16560). The tool didn't run against current apm-server stats. Three input-shape fixes, mirrored in both Go and the (out-of-band) Python reference used to regenerate goldens: - Read "output" from libbeat.output instead of top-level. If absent, skip silently and leave the upstream entries unchanged (warning to stderr). - Accept string scalars and emit them as type: keyword. - EA dispatch now matches "beat-stats-fields.yml" instead of "beat-fields.yml". Test fixture renamed accordingly. Goldens regenerated from the patched Python reference; Go matches byte-for-byte. Alias entries now emit {type, path} via a typed struct so field order matches Python (Go's map[string]any sorts alphabetically which would have flipped them to {path, type}). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
After elastic#20993 (eager monitoring counters) the /stats endpoint exposes the full enumerated set of apm-server.* metrics from the moment the server starts, including apm-server.sampling.tail.storage.disk_usage_threshold_pct, a Float64 gauge that's reported as 0.8 by default. Previously the tool aborted on non-integer numbers; map them to type "float" instead, matching the existing upstream typing in monitoring-beats*.json and the Beats / Integrations fields.yml files. Refresh the test fixtures: - testdata/stats.json: captured from a TBS-enabled apm-server built from the eager-monitoring-counters branch. Includes the float disk_usage_threshold_pct and the full eager-emitted counter set. - testdata/inputs/ea-beat-stats-fields.yml: re-snapshot from elastic/integrations main; the other four upstream snapshots were already current. - testdata/golden/*: regenerated from the new inputs and stats. Goldens now contain disk_usage_threshold_pct as type: float (typed files) or as an alias entry (beat-root-fields.yml), and the full set of otlp.{grpc,http}.{logs,metrics,traces} response error/valid families that previously only appeared after a matching response. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Contributor
🤖 GitHub commentsJust comment with:
|
License header indent normalized (tab -> 5 spaces) by the apm-server header tool. The package doc comment that the same tool stripped from main.go is preserved in cmd/stats-to-mapping/README.md. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Collaborator
💚 Build Succeeded
|
Contributor
|
This pull request does not have a backport label. Could you fix it @carsonip? 🙏
|
Member
Author
|
Closing this in favor of elastic/apm-tools#245 — moving the tool to apm-tools, since the testdata goldens are ~10k lines and the rest of the active devtools live there. The drift problem this is part of is now tracked in #21000. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation/summary
The five files that hold apm-server's field mappings live in three external repositories:
monitoring-beats.jsonandmonitoring-beats-mb.json(elastic/elasticsearchstack-monitoring templates)metricbeat/module/beat/_meta/fields.ymlandmetricbeat/module/beat/stats/_meta/fields.yml(elastic/beats)elastic_agent/data_stream/apm_server_metrics/fields/beat-stats-fields.yml(elastic/integrations)When apm-server adds, removes, or renames a metric, those five files must be hand-edited in three separate repos. The previously closed #13638 added a Python script that automated the regen by reading a single
/statssnapshot and rewriting each file in place. That PR was closed without merging, leaving us back at hand-editing.This PR ports the Python script to Go and homes it in apm-server at
cmd/stats-to-mapping, so a developer can regenerate the upstream mappings by pipingapm-server:5066/statsinto the binary with the five file paths as arguments. No Python venv, noruamel.yamldependency.This is the consumer side of the contract that #20993 (eager monitoring counters) restored: with that PR merged, a single
/statscapture from a freshly started apm-server enumerates every counter the server defines, sostats-to-mappingproduces a complete mapping set without needing to drive every error path during capture.What this changes
cmd/stats-to-mappingGo program. Same five-file contract as the closed Python script. Output is intentionally not byte-equal to the Python original — the Go implementation byte-splices the unchanged regions of input files (preserving comments, quoting, and surrounding whitespace) and re-emits the modified subtrees with stdlib JSON / YAML, sorted alphabetically.goTyperecognises non-integer JSON numbers and emitstype: float. The only such value today isapm-server.sampling.tail.storage.disk_usage_threshold_pct(introduced in #20464); upstream already types it asfloat, so this matches existing convention.cmd/stats-to-mapping/testdata/. The committedstats.jsonwas captured from a TBS-enabled apm-server built from #20993's eager-monitoring-counters branch, so the goldens reflect the full enumerated metric set the tool will see in production once that PR ships.cmd/stats-to-mapping/README.mdcovering build, invocation, supported files, and how the goldens were generated.Checklist
cmd/stats-to-mapping/.How to test these changes
go test ./cmd/stats-to-mapping/... go vet ./cmd/stats-to-mapping/...End-to-end against fresh upstream files:
Related issues
Supersedes the closed #13638. Unblocks the periodic upstream-mapping-sync work in #15533 and #13475. Best paired with #20993 so the captured
/statssnapshot is the complete enumeration.