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:
It records one Int64Countersubscription.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).
## 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)
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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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
subscriptionslibrary exposes anObserverinterface (Pushed/PushSkipped/Dropped/ChannelFull) but deliberately doesn't depend on OTel.otelsetupdoes. So*SubscriptionMetricssatisfies that interface structurally (otelsetup does not importsubscriptions), and each service wires it:It records one
Int64Countersubscription.notificationslabelled only bysubscription+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_fullflag 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-sidevar _ subscriptions.Observerguard 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 + accountingsubscription.New, + a Grafana skip/drop panel) lands once #782/#949 merge and this releases — tracked in Ambix (019ed07d).🤖 Generated with Claude Code
Coverage Report
Total coverage: 28%