Skip to content

fix(node): make validator metrics address configurable via flag/env#1023

Open
curryxbo wants to merge 1 commit into
mainfrom
fix/validator-metrics-port-config
Open

fix(node): make validator metrics address configurable via flag/env#1023
curryxbo wants to merge 1 commit into
mainfrom
fix/validator-metrics-port-config

Conversation

@curryxbo

@curryxbo curryxbo commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Problem

Before PR #966, a validator's metrics server was configurable through CLI flags / env vars:

  • --metrics-hostname / METRICS_HOSTNAME (default 0.0.0.0)
  • --metrics-port / METRICS_PORT (default 26660)
  • --metrics-server-enable / METRICS_SERVER_ENABLE

#966 removed all three. Layer1-verify validators now start their /metrics listener only from the Tendermint [instrumentation] prometheus_listen_addr in config.toml:

startMetricsServer(tmCfg.Instrumentation.PrometheusListenAddr, ...)

So operators who set a custom metrics port via --metrics-port / METRICS_PORT env silently lost that override — the value is ignored and the node falls back to the default :26660. The only way to change it now is editing config.toml.

Fix

Restore the flag/env override for the layer1 validator path only:

  • Re-add --metrics-hostname (METRICS_HOSTNAME) and --metrics-port (METRICS_PORT) — intentionally without default values, so an unset flag is distinguishable from an explicit one.
  • Resolve the metrics address with precedence explicit flag/env > config.toml prometheus_listen_addr > tendermint default, via a small resolveValidatorMetricsAddr helper.

Per discussion, --metrics-server-enable is not restored — reintroducing it with its old default (false) would silently disable validator metrics. Metrics stays on by default; to disable, set prometheus_listen_addr = "" in config.toml (already handled by startMetricsServer).

Behavior / compatibility

  • Neither flag set → unchanged: uses config.toml prometheus_listen_addr (default :26660).
  • --metrics-port / METRICS_PORT set → binds host:port (host defaults to all interfaces / 26660 if the other half is omitted).
  • Only affects layer1 (validator) mode; sequencer / local-verify fullnodes still get /metrics from the Tendermint listener as before.

Test

  • go build ./cmd/... ./flags/...
  • go vet ./cmd/node/

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added configurable metrics server hostname and port options.
    • Metrics settings can be provided through command-line flags or environment variables.
    • Existing instrumentation address behavior is preserved when overrides are not specified.

PR #966 dropped the --metrics-hostname / --metrics-port flags (and their
METRICS_HOSTNAME / METRICS_PORT env vars). Layer1-verify validators now
bind the /metrics listener solely to the Tendermint [instrumentation]
prometheus_listen_addr from config.toml, so operators who used to set a
custom port via flag/env can no longer override it.

Restore that override for the layer1 validator path: re-add the two flags
(no default value, so unset means "not provided") and resolve the metrics
address as explicit flag/env > config.toml prometheus_listen_addr. Default
behavior is unchanged -- with neither flag set the node keeps using the
config.toml address, and metrics stays on by default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@curryxbo
curryxbo requested a review from a team as a code owner July 17, 2026 10:35
@curryxbo
curryxbo requested review from dylanCai9 and removed request for a team July 17, 2026 10:35
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Layer1 verify mode now resolves the validator metrics address from optional CLI/environment overrides, with fallback to Tendermint configuration and a default port when only a hostname is provided.

Changes

Validator metrics overrides

Layer / File(s) Summary
Metrics flag definitions and registration
node/flags/flags.go
Adds metrics-hostname and metrics-port flags, derives their environment variables, and registers them in the node flag set.
Metrics address resolution
node/cmd/node/main.go
Resolves metrics overrides for Layer1 verify mode, defaults the port when needed, and preserves the configured address when no overrides are set.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: dylancai9

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI or environment
  participant Resolver as resolveValidatorMetricsAddr
  participant VerifyMode as Layer1 verify mode
  participant MetricsServer as Validator metrics server
  CLI->>Resolver: Provide metrics hostname and port
  Resolver->>VerifyMode: Return override or fallback address
  VerifyMode->>MetricsServer: Start server on resolved address
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed It clearly summarizes the main change: validator metrics address can now be configured via flags or environment variables.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/validator-metrics-port-config

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.


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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@node/cmd/node/main.go`:
- Around line 419-434: Update resolveValidatorMetricsAddr to use ctx.IsSet for
metrics hostname and port, preserving the fallback only when neither option is
set and retaining an explicitly provided port value of zero. Apply
defaultMetricsPort only when the port is genuinely unset, then construct the
address with net.JoinHostPort so IPv6 hosts are bracketed correctly; convert the
port to the required string form using strconv.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fa44c184-e866-45bc-9445-86ec7c0c4088

📥 Commits

Reviewing files that changed from the base of the PR and between 60a7515 and 7fce578.

📒 Files selected for processing (2)
  • node/cmd/node/main.go
  • node/flags/flags.go

Comment thread node/cmd/node/main.go
Comment on lines +419 to +434
// resolveValidatorMetricsAddr returns the address the layer1 validator metrics
// server binds to. The Tendermint [instrumentation] prometheus_listen_addr from
// config.toml is the default; an explicit --metrics-hostname / --metrics-port
// (or METRICS_HOSTNAME / METRICS_PORT) overrides it. The flags carry no default
// value, so an empty host and zero port mean "not set" and the fallback is kept.
func resolveValidatorMetricsAddr(ctx *cli.Context, fallback string) string {
host := ctx.GlobalString(flags.MetricsHostname.Name)
port := ctx.GlobalUint64(flags.MetricsPort.Name)
if host == "" && port == 0 {
return fallback
}
if port == 0 {
port = defaultMetricsPort
}
return fmt.Sprintf("%s:%d", host, port)
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use net.JoinHostPort for safe address construction.

Concatenating the host and port with fmt.Sprintf("%s:%d", host, port) produces an invalid TCP address if an IPv6 hostname is provided (e.g., ::1:26660 instead of [::1]:26660), which will cause the metrics server to fail on startup. Use net.JoinHostPort to safely format the address.

Additionally, the PR description notes that unset options should remain distinguishable from explicit values. However, checking port == 0 cannot distinguish between an unset flag and an explicitly provided --metrics-port 0 (which gets incorrectly overwritten to 26660). If your version of urfave/cli reliably supports ctx.IsSet for environment variables, consider using it instead of zero-value checks to genuinely distinguish unset flags.

🛠️ Proposed fix
 func resolveValidatorMetricsAddr(ctx *cli.Context, fallback string) string {
 	host := ctx.GlobalString(flags.MetricsHostname.Name)
 	port := ctx.GlobalUint64(flags.MetricsPort.Name)
 	if host == "" && port == 0 {
 		return fallback
 	}
 	if port == 0 {
 		port = defaultMetricsPort
 	}
-	return fmt.Sprintf("%s:%d", host, port)
+	return net.JoinHostPort(host, strconv.FormatUint(port, 10))
 }

Ensure that "net" and "strconv" are imported at the top of the file if not already present.

📝 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
// resolveValidatorMetricsAddr returns the address the layer1 validator metrics
// server binds to. The Tendermint [instrumentation] prometheus_listen_addr from
// config.toml is the default; an explicit --metrics-hostname / --metrics-port
// (or METRICS_HOSTNAME / METRICS_PORT) overrides it. The flags carry no default
// value, so an empty host and zero port mean "not set" and the fallback is kept.
func resolveValidatorMetricsAddr(ctx *cli.Context, fallback string) string {
host := ctx.GlobalString(flags.MetricsHostname.Name)
port := ctx.GlobalUint64(flags.MetricsPort.Name)
if host == "" && port == 0 {
return fallback
}
if port == 0 {
port = defaultMetricsPort
}
return fmt.Sprintf("%s:%d", host, port)
}
// resolveValidatorMetricsAddr returns the address the layer1 validator metrics
// server binds to. The Tendermint [instrumentation] prometheus_listen_addr from
// config.toml is the default; an explicit --metrics-hostname / --metrics-port
// (or METRICS_HOSTNAME / METRICS_PORT) overrides it. The flags carry no default
// value, so an empty host and zero port mean "not set" and the fallback is kept.
func resolveValidatorMetricsAddr(ctx *cli.Context, fallback string) string {
host := ctx.GlobalString(flags.MetricsHostname.Name)
port := ctx.GlobalUint64(flags.MetricsPort.Name)
if host == "" && port == 0 {
return fallback
}
if port == 0 {
port = defaultMetricsPort
}
return net.JoinHostPort(host, strconv.FormatUint(port, 10))
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@node/cmd/node/main.go` around lines 419 - 434, Update
resolveValidatorMetricsAddr to use ctx.IsSet for metrics hostname and port,
preserving the fallback only when neither option is set and retaining an
explicitly provided port value of zero. Apply defaultMetricsPort only when the
port is genuinely unset, then construct the address with net.JoinHostPort so
IPv6 hosts are bracketed correctly; convert the port to the required string form
using strconv.

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.

1 participant