Skip to content

feat(eth2api): add Charon-parity beacon node request metrics - #573

Merged
varex83agent merged 4 commits into
mainfrom
feat/eth2wrap-request-metrics
Jul 30, 2026
Merged

feat(eth2api): add Charon-parity beacon node request metrics#573
varex83agent merged 4 commits into
mainfrom
feat/eth2wrap-request-metrics

Conversation

@varex83

@varex83 varex83 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds Charon eth2wrap-parity Prometheus metrics for beacon node requests, using Pluto's vise conventions (not the prometheus crate, which Pluto doesn't use):

  • app_eth2_requests_total{endpoint}
  • app_eth2_errors_total{endpoint}
  • app_eth2_latency_seconds{endpoint} — with Charon's exact 17 latency buckets

Metric names match Charon's app_eth2_* series. They're defined in a new crates/eth2api/src/metrics.rs and auto-registered via #[vise::register], so the existing /metrics endpoint surfaces them with no extra wiring.

A small instrument(endpoint, fut) helper reproduces Charon's per-call semantics — record a request + observe latency always, increment errors on Err — and slots in ahead of the existing .map_err(...) handling at each call site (the generated client methods return anyhow::Result, so caller types are preserved).

Coverage

Instruments the endpoints Pluto actually calls today, using Charon's snake_case labels:

  • Inside existing eth2api wrappers (zero call-site churn): attester_duties, all submit_* duties, spec, genesis, fork_schedule, validators.
  • Inline at core/app call sites: proposal, attestation_data, sync_committee_contribution, aggregate_attestation, proposer_duties, sync_committee_duties, node_syncing, node_version, node_peer_count.

Endpoints Charon instruments but Pluto doesn't call yet (e.g. beacon_block_root, the *_selections, prepare_sync_committee_subnets) are intentionally skipped — each is now a one-line instrument(...) addition when the port reaches them.

Deliberate deviations from Charon

  1. using_fallback gauge omitted — Pluto has no multi/fallback beacon client yet (Implement app/app.go equivalent — node graph wiring & lifecycle #402 part B). To be added when fallback lands.
  2. errors_total counts transport/decode Err only, not HTTP 4xx/5xx. Charon's go-eth2-client returns an error on non-2xx; Pluto's generated client returns Ok(Response::BadRequest(..)) for 4xx, which wrappers convert to Err after the instrumented call. Full error-count parity would require instrumenting around response classification — can follow up if exact parity is wanted.

Testing

  • cargo +nightly fmt --all --check
  • cargo clippy -p pluto-eth2api -p pluto-core -p pluto-app --all-targets --all-features ✅ (clean)
  • cargo test: eth2api (119) ✅, core (600) ✅, app ✅ — includes new unit tests asserting the exposition text and all latency buckets.

🤖 Generated with Claude Code

varex83 added 3 commits July 30, 2026 13:22
Adds `app_eth2_requests_total`, `app_eth2_errors_total`, and
`app_eth2_latency_seconds` (with Charon's exact latency buckets),
labelled by logical endpoint, mirroring Charon's eth2wrap metrics.

Defined via the workspace `vise` conventions and auto-registered, so
the existing `/metrics` endpoint surfaces them with no extra wiring.
A small `instrument()` helper reproduces Charon's per-call semantics
(record request + latency always, error on `Err`) and slots in ahead
of the existing response handling.

Instruments the endpoints Pluto calls today using Charon's snake_case
labels: inside existing eth2api wrappers (attester duties, all submit
duties, spec, genesis, fork_schedule, validators) and inline at the
core/app call sites (proposal, attestation_data,
sync_committee_contribution, aggregate_attestation, proposer_duties,
sync_committee_duties, node_syncing, node_version, node_peer_count).

The `using_fallback` gauge is omitted until a multi/fallback beacon
client exists (#402 part B).
…-metrics

# Conflicts:
#	crates/core/src/scheduler.rs
#	crates/eth2api/src/extensions.rs
Locks in the `/metrics` OpenMetrics-for-Prometheus series names, the
`endpoint` label, and the monitoring API's global `cluster_*` labels
that the beacon-node health Grafana panel queries, guarding against a
double `_total` counter suffix.
Comment thread crates/eth2api/src/metrics.rs Outdated
Comment thread crates/core/src/scheduler.rs Outdated
Comment thread crates/core/src/validatorapi/component.rs Outdated
…l sites

Addresses PR #573 review:

- errors_total now counts non-2xx beacon-node responses, not just
  transport/decode Err. The generated client returns Ok(Response::BadRequest(..))
  for HTTP errors, so is_err() alone never fired. A new BeaconResponse trait
  (impl'd per response enum via macro) lets instrument classify 2xx vs error,
  matching Charon eth2wrap semantics.
- Wrap the two remaining get_attester_duties call sites (scheduler
  fetch_attester_duties and the validatorapi handler) in instrument("attester_duties", ..).

Co-Authored-By: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
@varex83agent
varex83agent merged commit 820e718 into main Jul 30, 2026
11 checks passed
@varex83agent
varex83agent deleted the feat/eth2wrap-request-metrics branch July 30, 2026 17:16
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.

3 participants