feat(metrics): 3 Prometheus counters for scaling dive (#7756)

Merged
JO
5mo ago
+203-1

Summary

Adds three Prometheus rows to `/stats/prometheus` so the load-test harness for #7756 can attribute where time goes on the server, not just the gauge headline (CPU / event-loop / memory):

  • `etherpad_pad_users{padId}` — gauge derived from `sessioninfos` on scrape. Lets the harness confirm a target pad actually has the expected concurrency.
  • `etherpad_changeset_apply_duration_seconds` — histogram observed inside `handleUserChanges`. Separates "apply path is slow" from "fan-out is slow" when latency rises.
  • `etherpad_socket_emits_total{type}` — counter at the broadcast emit sites (`handleCustomObjectMessage`, `handleCustomMessage`, `sendChatMessageToPadClients`) and the per-socket `NEW_CHANGES` loop in `updatePadClients`. Bucketed by message type so the harness can measure the amplification factor of each lever (especially the fan-out batching lever).

Metric handles live in a new `src/node/prom-instruments.ts` rather than `prometheus.ts` itself, to avoid a circular import — `prometheus.ts` already `require`s `PadMessageHandler` to read `sessioninfos`.

This is the follow-up PR planned in section 6 of `docs/superpowers/specs/2026-05-15-scaling-dive-design.md` (in `ether/etherpad-load-test`). The load-test harness already tolerates these metrics' absence, so it ships unblocked; this PR just makes the next dive run more informative.

Test Plan

  • Backend test `src/tests/backend-new/specs/prom-instruments.test.ts` passes (3/3 locally) — verifies the recording helpers move the underlying counter/histogram.
  • Existing backend test suite remains green.
  • After merge, `curl http://your-etherpad/stats/prometheus | grep etherpad_` shows the three new rows.
  • Trigger the Scaling dive workflow with `core_ref` pointing at this branch or develop-post-merge; verify the harness reports include `etherpad_socket_emits_total{type=NEW_CHANGES}` and `etherpad_changeset_apply_duration_seconds_count` in the JSON snapshot.

🤖 Generated with Claude Code