Skip to content

Add service.instance.id to mailroom telemetry resource#1745

Draft
DanGould wants to merge 2 commits into
payjoin:masterfrom
DanGould:agent/mailroom-otel-instance-id
Draft

Add service.instance.id to mailroom telemetry resource#1745
DanGould wants to merge 2 commits into
payjoin:masterfrom
DanGould:agent/mailroom-otel-instance-id

Conversation

@DanGould

Copy link
Copy Markdown
Member

PR body draft — agent/mailroom-otel-instance-id

Title: Add service.instance.id to mailroom telemetry resource


Every mailroom node pushes OTLP metrics with a resource of only
service.name + operator.domain. Grafana Cloud maps service.nameto job
and service.instance.id to instance. Other resource attributes land only in
target_info. With no service.instance.id, every node shares identical
series identity, so cumulative counters from N processes interleave inside
ONE stored series per metric. Prometheus rate() reads each backward jump as
a counter reset and re-adds roughly the full counter value.

Observed in production: 5 nodes reporting (count(target_info) = 5) but a
single series for the label-less http_requests_started_total. The dashboard
rendered a climbing ~100k req/s sawtooth from a service doing ~5 req/s (the
counter never exceeded ~5.5M — a genuine 100k/s over a 4-minute rate window
would require 24M of increase).

Fix: attach a per-boot service.instance.id (UUID v4) so each process gets
its own series.

  • Commit 1 extracts the Resource construction out of main.rs into the
    library so it is testable — contrib/test.sh only runs --lib and
    --test integration targets, so a test in the binary would never run in CI.
  • Commit 2 adds the attribute. uuid is promoted from dev-dependency to an
    optional dependency of the telemetry feature; both lockfiles already
    pinned uuid 1.18.0, so there is no lockfile change.

Tests assert service.name, operator.domain, and that
service.instance.id is present, non-empty, parses as a UUID, and differs
across constructions. Local gates green: fmt, codespell, clippy
(--all-features and --no-default-features), 65 lib + 3 integration tests,
contrib/lint.sh, doc lint (-D warnings), nix fmt -- --ci.

Nodes must redeploy to benefit; until all operators update, non-upgraded
senders continue to collide with each other (mitigable stack-side by
promoting the operator.domain resource attribute onto metrics).

Disclosure: co-authored by Claude Code

DanGould added 2 commits July 8, 2026 16:26
Move the OTLP Resource construction out of the binary's
init_tracing_with_telemetry into a library function
build_telemetry_resource, gated #[cfg(feature = "telemetry")].

contrib/test.sh only runs --lib and --test integration targets,
so any test in main.rs would never run in CI. The extraction
puts the construction where it can be tested.

Unit test verifies service.name = "payjoin-mailroom" and
operator.domain equals the configured value.
Each call to build_telemetry_resource now generates a UUID v4 and
adds it as service.instance.id. Grafana Cloud maps this attribute to
the Prometheus instance label, giving each process its own series so
cumulative counters no longer interleave across nodes.

uuid is added to [dependencies] as optional, activated by the
telemetry feature. The dev-dependency is kept because the integration
test uses uuid unconditionally (not behind a feature gate).

Test extended: service.instance.id is present, non-empty, parses as
a UUID, and differs across two constructions (verifying per-boot
uniqueness). TODO-TESTS.md deleted.

Cargo-minimal.lock: uuid 1.18.0 was already pinned as a dev-dep in
upstream's lockfile; no new entries are required for the promotion
to optional regular dep (verified: cargo check --locked --all-features
--all-targets passes against the unmodified upstream lockfile). A
from-scratch regen churns ~2700 lines of unrelated environmental drift
(crates.io index moved since the file was last committed); the lockfile
is therefore left at the upstream-committed pins.
@coveralls

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 29486348286

Coverage increased (+0.04%) to 86.227%

Details

  • Coverage increased (+0.04%) from the base build.
  • Patch coverage: 1 uncovered change across 1 file (28 of 29 lines covered, 96.55%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
payjoin-mailroom/src/main.rs 1 0 0.0%
Total (2 files) 29 28 96.55%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 15988
Covered Lines: 13786
Line Coverage: 86.23%
Coverage Strength: 345.12 hits per line

💛 - Coveralls

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants