Skip to content

fix(aleo): normalize method labels in metrics to prevent high cardinality#7989

Closed
nambrot-agent wants to merge 1 commit intomainfrom
fix/aleo-metrics-method-label
Closed

fix(aleo): normalize method labels in metrics to prevent high cardinality#7989
nambrot-agent wants to merge 1 commit intomainfrom
fix/aleo-metrics-method-label

Conversation

@nambrot-agent
Copy link
Copy Markdown
Contributor

@nambrot-agent nambrot-agent commented Feb 1, 2026

Summary

Fixes a bug where the Aleo chain adapter was putting dynamic values (like block numbers) in the Prometheus method label, creating a new metric series for every unique API call.

Before:

method="block/15544045"
method="block/15544065"
method="transaction/at0abc123..."

→ ~3,359 unique method values for Aleo (vs ~14 expected)

After:

method="get_block"
method="get_transaction"
method="get_mapping_value"

→ ~14 unique method values (matching other chains like Ethereum)

Changes

  • Added normalize_method() function in rust/main/chains/hyperlane-aleo/src/provider/metric.rs that maps dynamic API paths to static method names
  • Updated track_request() to use the normalized method name instead of the raw path

Impact

This fix eliminates ~6,700 unnecessary metric series caused by high-cardinality labels from the Aleo adapter.

Summary by CodeRabbit

  • Refactor
    • Enhanced internal metrics collection by normalizing API endpoint categorization, reducing redundant labels and improving system performance observability and monitoring accuracy.

✏️ Tip: You can customize this high-level summary in your review settings.

…lity

The Aleo adapter was using full API paths (including dynamic values like
block numbers) as the method label in Prometheus metrics. This created
thousands of unique metric series (e.g., method="block/15544045").

This fix adds a normalize_method() function that maps dynamic paths to
static method names, reducing unique method values from ~3,359 to ~14.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

This change introduces a normalize_method() function that maps dynamic API paths to static metric labels, replacing a simplistic path-splitting approach. The function handles block, program, transaction, state, and other endpoint variants to reduce high-cardinality metrics.

Changes

Cohort / File(s) Summary
Metric Path Normalization
rust/main/chains/hyperlane-aleo/src/provider/metric.rs
Adds normalize_method(path: &str) -> &'static str function to categorize API paths into bounded metric labels with explicit handling for block, program, transaction, state, and state_paths variants. Updates track_request() to use this normalized mapping instead of naive path segment extraction.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • ameten

Poem

Paths have their layers, like ogres, ye see,
From blocks to programs, from states wild and free,
No more high cardinality's messy charade,
Just normalized labels, a tidy cascade! 🧅📊

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: normalizing method labels in Aleo metrics to prevent high cardinality issues.
Description check ✅ Passed The PR description covers all required template sections with clear context, specific before/after examples, detailed changes, and quantified impact.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/aleo-metrics-method-label

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@rust/main/chains/hyperlane-aleo/src/provider/metric.rs`:
- Around line 56-61: The metric path matcher is too permissive: the branch using
path.starts_with("statePaths") can misclassify endpoints like "statePathsFoo";
update the condition in the same matcher where path.starts_with("statePath/")
returns "get_state_path" and the branch that returns "get_state_paths" so it
only matches exactly "statePaths" or "statePaths/" (or otherwise checks for a
trailing slash) instead of a bare starts_with; modify the
path.starts_with("statePaths") check to require equality or a slash-aware check
so only the intended "get_state_paths" endpoint is labeled.

Comment on lines +56 to +61
if path.starts_with("statePath/") {
return "get_state_path";
}
if path.starts_with("statePaths") {
return "get_state_paths";
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Tighten the statePaths match to avoid accidental collisions.

starts_with("statePaths") will also match any future endpoints like statePathsFoo, which would mislabel metrics. Safer to require an exact match or a slash.

Suggested tweak
-    if path.starts_with("statePaths") {
+    if path == "statePaths" || path.starts_with("statePaths/") {
         return "get_state_paths";
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if path.starts_with("statePath/") {
return "get_state_path";
}
if path.starts_with("statePaths") {
return "get_state_paths";
}
if path.starts_with("statePath/") {
return "get_state_path";
}
if path == "statePaths" || path.starts_with("statePaths/") {
return "get_state_paths";
}
🤖 Prompt for AI Agents
In `@rust/main/chains/hyperlane-aleo/src/provider/metric.rs` around lines 56 - 61,
The metric path matcher is too permissive: the branch using
path.starts_with("statePaths") can misclassify endpoints like "statePathsFoo";
update the condition in the same matcher where path.starts_with("statePath/")
returns "get_state_path" and the branch that returns "get_state_paths" so it
only matches exactly "statePaths" or "statePaths/" (or otherwise checks for a
trailing slash) instead of a bare starts_with; modify the
path.starts_with("statePaths") check to require equality or a slash-aware check
so only the intended "get_state_paths" endpoint is labeled.

@hyper-gonk
Copy link
Copy Markdown
Contributor

hyper-gonk Bot commented Feb 1, 2026

🦀 Rust Agent Docker Image Built Successfully

Service Tag
agent 1c2c37e-20260201-225932
Full image paths
gcr.io/abacus-labs-dev/hyperlane-agent:1c2c37e-20260201-225932

@paulbalaji
Copy link
Copy Markdown
Collaborator

@claude review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 2, 2026

Claude finished @paulbalaji's task in 1m 4s —— View job


Code Review: Aleo Metrics Method Label Normalization

  • Analyze the code changes
  • Check for logic errors and edge cases
  • Review pattern consistency with codebase
  • Provide actionable feedback

Overall: Good fix that correctly addresses the high-cardinality metrics issue. The approach is sound and matches the problem statement.

Issues to Address

1. statePaths match is too permissive (line 59)

The current check starts_with("statePaths") would match hypothetical endpoints like statePathsFoo. Looking at traits.rs:329,347, the actual usage is statePaths?commitments=..., so the query string format needs proper handling.

// Current (problematic)
if path.starts_with("statePaths") {

// Better - handles the query string case
if path == "statePaths" || path.starts_with("statePaths?") {

Fix this →

Suggestions (Non-blocking)

2. Consider adding unit tests for normalize_method

The function has multiple branches with order-dependent logic. Unit tests would:

  • Document expected behavior for each endpoint pattern
  • Prevent regressions if new endpoints are added
  • Make the order-dependency explicit

Example test cases:

#[test]
fn test_normalize_method() {
    assert_eq!(normalize_method("block/15544045"), "get_block");
    assert_eq!(normalize_method("block/latest"), "block/latest");
    assert_eq!(normalize_method("block/123/transactions"), "get_block_transactions");
    assert_eq!(normalize_method("statePaths?commitments=abc"), "get_state_paths");
    assert_eq!(normalize_method("unknown/endpoint"), "unknown");
}

3. Minor inconsistency in naming convention

Static paths keep their original names ("block/latest", "transaction/broadcast") while dynamic paths use get_* format. This works but may be worth documenting.

What Looks Good

  • Clear docstring explaining the purpose
  • Order-dependent matching is correctly structured (more specific patterns before general ones)
  • Covers all endpoint patterns used in traits.rs
  • Returns "unknown" for unmatched paths (safe fallback)
  • The fix at line 135 correctly integrates with the existing metrics infrastructure

@paulbalaji
Copy link
Copy Markdown
Collaborator

Review Summary

Already Caught (ACK)

  • statePaths matcher too permissive — CodeRabbit & Claude CI both flagged
  • ✅ Unit tests recommended — Claude CI flagged
  • ✅ Overall approach is correct and aligns with other chain adapters

Additional Findings

  1. 🔴 CI is failing on rustfmt — Needs cd rust/main && cargo fmt before merge.

  2. CodeRabbit's suggested fix needs adjustment — It suggested statePaths/ but actual usage in traits.rs:329,347 is statePaths?commitments=... (query string). The correct fix:

    if path == "statePaths" || path.starts_with("statePaths?") {

TL;DR

Good PR, fix rustfmt, use ? not / for statePaths matcher.

@nambrot nambrot closed this Feb 2, 2026
@github-project-automation github-project-automation Bot moved this from In Review to Done in Hyperlane Tasks Feb 2, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.02%. Comparing base (cf80e8f) to head (1c2c37e).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7989   +/-   ##
=======================================
  Coverage   77.02%   77.02%           
=======================================
  Files         117      117           
  Lines        2651     2651           
  Branches      244      244           
=======================================
  Hits         2042     2042           
  Misses        593      593           
  Partials       16       16           
Components Coverage Δ
core 87.80% <ø> (ø)
hooks 71.86% <ø> (ø)
isms 81.10% <ø> (ø)
token 86.67% <ø> (ø)
middlewares 84.98% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants