feat(metrics): add SubscriptionMetrics OTel observer for subscriptions #150

Merged
argoyle merged 1 commits from feat/subscription-metrics into main 2026-06-16 13:14:16 +00:00
Owner

What

Adds otelsetup.NewSubscriptionMetrics(subscription string) — an OTel observer for the cross-service read-your-writes subscriptions (ADR-0012). This is the home for the skip/drop metrics flagged as a follow-up in both subscription-lib migration reviews (authz #782, accounting #949).

Why / how

The subscriptions library exposes an Observer interface (Pushed/PushSkipped/Dropped/ChannelFull) but deliberately doesn't depend on OTel. otelsetup does. So *SubscriptionMetrics satisfies that interface structurally (otelsetup does not import subscriptions), and each service wires it:

metrics, err := otelsetup.NewSubscriptionMetrics("availableCompanies")
reg := subscriptions.New[T](subscriptions.WithObserver(metrics))

It records one Int64Counter subscription.notifications labelled only by subscription + outcome (pushed/skipped/dropped/channel_full). The subscriber key (company id / user email) is intentionally NOT a label — that would be unbounded cardinality; the key stays in the library's logs. skip-rate = skipped / (pushed + skipped) is the alert-worthy signal (chronic projection lag); dropped/channel_full flag burst back-pressure / stuck clients.

Review

Infrastructure Expert — sound, ship-ready, no Critical/High. Confirmed: the single-counter-with-outcome-attribute is the right shape (matches the eventsourced adapter's boolean-attribute idiom); cardinality is bounded; context.Background() is fine for a counter; no-op-when-disabled is free; naming/units match house style; auto-tag will cut v0.4.0 (feat → minor; do not hand-edit .version/CHANGELOG). Addressed: corrected the non-compiling usage snippet in the doc, marked the structural-guard coupling (consumer-side var _ subscriptions.Observer guard to be added in the service wiring), and added a disabled-provider test.

Tests

go build/vet/gofumpt/goimports, go test -race, golangci-lint, prek all green. Tests assert per-outcome counts, the cardinality guard (distinct keys → one series per outcome), and the no-op-provider safety.

Follow-up

The per-service wiring (pass WithObserver(otelsetup.NewSubscriptionMetrics(...)) in authz + accounting subscription.New, + a Grafana skip/drop panel) lands once #782/#949 merge and this releases — tracked in Ambix (019ed07d).

🤖 Generated with Claude Code

## What Adds `otelsetup.NewSubscriptionMetrics(subscription string)` — an OTel observer for the cross-service read-your-writes subscriptions (ADR-0012). This is the home for the skip/drop metrics flagged as a follow-up in both subscription-lib migration reviews (authz #782, accounting #949). ## Why / how The `subscriptions` library exposes an `Observer` interface (`Pushed`/`PushSkipped`/`Dropped`/`ChannelFull`) but deliberately doesn't depend on OTel. `otelsetup` does. So `*SubscriptionMetrics` satisfies that interface **structurally** (otelsetup does **not** import `subscriptions`), and each service wires it: ```go metrics, err := otelsetup.NewSubscriptionMetrics("availableCompanies") reg := subscriptions.New[T](subscriptions.WithObserver(metrics)) ``` It records one `Int64Counter` `subscription.notifications` labelled only by `subscription` + `outcome` (pushed/skipped/dropped/channel_full). **The subscriber key (company id / user email) is intentionally NOT a label** — that would be unbounded cardinality; the key stays in the library's logs. `skip-rate = skipped / (pushed + skipped)` is the alert-worthy signal (chronic projection lag); `dropped`/`channel_full` flag burst back-pressure / stuck clients. ## Review Infrastructure Expert — sound, ship-ready, no Critical/High. Confirmed: the single-counter-with-`outcome`-attribute is the right shape (matches the eventsourced adapter's boolean-attribute idiom); cardinality is bounded; `context.Background()` is fine for a counter; no-op-when-disabled is free; naming/units match house style; auto-tag will cut **v0.4.0** (`feat` → minor; do not hand-edit `.version`/`CHANGELOG`). Addressed: corrected the non-compiling usage snippet in the doc, marked the structural-guard coupling (consumer-side `var _ subscriptions.Observer` guard to be added in the service wiring), and added a disabled-provider test. ## Tests `go build`/`vet`/`gofumpt`/`goimports`, `go test -race`, golangci-lint, prek all green. Tests assert per-outcome counts, the cardinality guard (distinct keys → one series per outcome), and the no-op-provider safety. ## Follow-up The per-service wiring (pass `WithObserver(otelsetup.NewSubscriptionMetrics(...))` in authz + accounting `subscription.New`, + a Grafana skip/drop panel) lands once #782/#949 merge and this releases — tracked in Ambix (019ed07d). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
argoyle added 1 commit 2026-06-16 13:08:02 +00:00
feat(metrics): add SubscriptionMetrics OTel observer for read-your-writes subscriptions
otelsetup / vulnerabilities (pull_request) Successful in 1m39s
otelsetup / test (pull_request) Successful in 2m42s
pre-commit / pre-commit (pull_request) Successful in 5m33s
cb99bbc1a6
NewSubscriptionMetrics(subscription) returns a *SubscriptionMetrics whose method
set (Pushed/PushSkipped/Dropped/ChannelFull) satisfies the Observer interface of
gitea.unbound.se/shiny/subscriptions structurally — otelsetup does not import
that library. Services wire it via subscriptions.WithObserver so the
cross-service subscription push path (ADR-0012) reports outcomes as metrics
instead of only the library's skip/drop warn logs.

One Int64Counter `subscription.notifications` labelled by (subscription, outcome)
only — the subscriber key (company id / user email) is deliberately NOT a label
to avoid unbounded cardinality. skip-rate = skipped/(pushed+skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
argoyle scheduled this pull request to auto merge when all checks succeed 2026-06-16 13:08:05 +00:00

Coverage Report

Total coverage: 28%

## Coverage Report Total coverage: **28%**
argoyle merged commit c00564cdcb into main 2026-06-16 13:14:16 +00:00
argoyle deleted branch feat/subscription-metrics 2026-06-16 13:14:17 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: shiny/otelsetup#150