mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-07-17 16:47:05 +00:00
* docs: refresh docs for 3.2.0 — correct stale content, document recent features The hand-maintained VitePress docs under doc/ had drifted behind a lot of recent work. They are authored prose (not generated from the OpenAPI spec), so they need manual upkeep. This pass corrects content that was actively wrong and documents features shipped since they were last touched. Corrections (was wrong / misleading): - cli.md: every command used `node bin/foo.js`, but the scripts are TypeScript run via pnpm — copy-paste failed. Rewrote to `pnpm run --filter bin <script>`, documented ~13 previously-undocumented operator tools, and split running-vs-stopped requirements. Registered the missing `compactStalePads` script in bin/package.json so the documented invocation actually works. - stats.md: described a pre-Prometheus world. Rewrote for the gated `/stats` (JSON) and `/stats/prometheus` endpoints, the live metric set, the opt-in `scalingDiveMetrics` instruments (#7756), and `measured-core`. - admin/updates.md: removed three false "SMTP not yet wired" claims (it is, via nodemailer + the `mail.*` block), documented the `node-engine-mismatch` preflight check and the rollback/preflight failure emails, and stripped obsolete "PR 1 / PR 2" staging language now that all tiers ship. - api/http_api.md: added the undocumented `anonymizeAuthor` (GDPR Art. 17) call, fixed copyPad/movePad version annotations (1.2.8 → 1.2.9), corrected getPadID's param name (readOnlyID → roID), and dropped a reference to a non-existent `getEtherpad` API call. - skins.md: colibris is the current default, not an "experimental" skin for a future 2.0. - localization.md: bare `window._('key')` is unbound and returns undefined; recommend `window.html10n.get(...)` / data-l10n-id instead. - README.md: bumped the v2.2.5 upgrade example to v3.2.0; fixed a docker.adoc link to docker.md. - docker.md: added MAIL_*, ENABLE_METRICS, GDPR_AUTHOR_ERASURE_ENABLED, PRIVACY_BANNER_*, PUBLIC_URL, AUTHENTICATION_METHOD, ENABLE_DARK_MODE, ENABLE_PAD_WIDE_SETTINGS; fixed the SOCKETIO_MAX_HTTP_BUFFER_SIZE default (50000 → 1000000). New documentation: - configuration.md (new): how settings + `${VAR:default}` substitution work, trustProxy, and — the previously-undocumented feature — running under a subpath/ingress via x-proxy-path / X-Forwarded-Prefix / X-Ingress-Path, with the sanitizer rules and Traefik/NGINX examples. Wired into the VitePress sidebar and the index hero. - hooks_server-side.md: ccRegisterBlockElements (the server-side companion plugin authors miss), exportConvert, exportHTMLSend, createServer, restartServer, and clientReady (marked deprecated). - hooks_client-side.md: aceDrop, acePaste, handleClientTimesliderMessage_<name>. VitePress build passes. The legacy .adoc set was intentionally left in place — it still feeds the per-version doc archives published to ether.github.com at release time (bin/release.ts), so it is not dead and is out of scope here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: address Qodo review — drop .js invocations from configuration.md and CLI help - configuration.md: the settings-override example referenced a nonexistent `node src/node/server.js`. Use the supported launcher instead (`bin/run.sh -s <file>`), and note the runtime is server.ts via tsx. - compactStalePads.ts / compactPad.ts / compactAllPads.ts: their header comments and runtime usage output still printed `node bin/*.js`, which points at files that don't exist. Switched to the documented `pnpm run --filter bin <script>` form so the --help text matches the docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
147 lines
6.3 KiB
Markdown
147 lines
6.3 KiB
Markdown
# Statistics and metrics
|
|
|
|
Etherpad tracks runtime statistics about the edit machinery, the database
|
|
layer, and the Node.js process, and can expose them over HTTP for monitoring.
|
|
|
|
There are two endpoints:
|
|
|
|
- `GET /stats` — a JSON dump of the internal `measured-core` collection.
|
|
- `GET /stats/prometheus` — the same kind of data (plus process/runtime
|
|
metrics) in the [Prometheus](https://prometheus.io/) text exposition format.
|
|
|
|
## Enabling the endpoints
|
|
|
|
Both endpoints are gated behind the `enableMetrics` setting, which defaults to
|
|
`true`:
|
|
|
|
```json
|
|
{
|
|
"enableMetrics": true
|
|
}
|
|
```
|
|
|
|
When `enableMetrics` is `false` the routes are **not registered at all** — a
|
|
request to `/stats` or `/stats/prometheus` returns the normal 404 handling, not
|
|
an empty response. The admin-panel statistics view is unaffected by this
|
|
setting.
|
|
|
|
## `GET /stats` (JSON)
|
|
|
|
Returns the current snapshot of the `measured-core` collection as JSON. The
|
|
following metrics are collected:
|
|
|
|
| Metric | Type | Meaning |
|
|
| --- | --- | --- |
|
|
| `totalUsers` | gauge | Number of users currently connected across all pads. |
|
|
| `activePads` | gauge | Number of pads with at least one connected user. |
|
|
| `connects` | meter | Rate of new client connections. |
|
|
| `disconnects` | meter | Rate of client disconnections. |
|
|
| `rateLimited` | meter | Rate of messages dropped by the per-connection rate limiter. |
|
|
| `pendingEdits` | counter | Edits received but not yet fully processed. |
|
|
| `edits` | timer | Time taken to process an incoming `USER_CHANGES` edit (full handler span). |
|
|
| `failedChangesets` | meter | Rate of changesets that failed to apply. |
|
|
| `httpRequests` | timer | Duration of HTTP requests served by Express. |
|
|
| `http500` | meter | Rate of HTTP 500 responses. |
|
|
| `memoryUsage` | gauge | Process resident set size (`process.memoryUsage().rss`). |
|
|
| `memoryUsageHeap` | gauge | Process heap usage (`process.memoryUsage().heapUsed`). |
|
|
| `lastDisconnect` | gauge | Timestamp (ms) of the most recent socket disconnect. |
|
|
| `ueberdb_*` | gauge | One gauge per [ueberDB](https://github.com/ether/ueberDB) database statistic, e.g. read/write counts and timings (`ueberdb_reads`, `ueberdb_writes`, …). The exact set depends on the configured database driver. |
|
|
|
|
Under the hood these are provided by
|
|
[`measured-core`](https://github.com/yaorg/node-measured/tree/master/packages/measured-core).
|
|
To read or extend them from a plugin, require the shared collection:
|
|
|
|
```js
|
|
const stats = require('ep_etherpad-lite/node/stats');
|
|
// stats is a measured-core Collection
|
|
stats.counter('my_plugin_events').inc();
|
|
console.log(stats.toJSON());
|
|
```
|
|
|
|
## `GET /stats/prometheus` (Prometheus exposition format)
|
|
|
|
Served from a dedicated [`prom-client`](https://github.com/siimon/prom-client)
|
|
registry. This is the endpoint you point a Prometheus scraper at.
|
|
|
|
### Metrics exposed by default
|
|
|
|
| Metric | Type | Labels | Meaning |
|
|
| --- | --- | --- | --- |
|
|
| `etherpad_total_users` | gauge | — | Total number of connected users. |
|
|
| `etherpad_active_pads` | gauge | — | Total number of active pads. |
|
|
| `ueberdb_stats` | gauge | `type` | ueberDB statistics, one series per numeric ueberDB metric (the metric name is carried in the `type` label). |
|
|
|
|
In addition, the registry calls `prom-client`'s `collectDefaultMetrics()`, so
|
|
the standard Node.js / process metrics are also exposed, including (names as
|
|
emitted by `prom-client`):
|
|
|
|
- `process_cpu_user_seconds_total`, `process_cpu_system_seconds_total`,
|
|
`process_cpu_seconds_total`
|
|
- `process_resident_memory_bytes`, `process_heap_bytes`,
|
|
`process_virtual_memory_bytes`
|
|
- `process_open_fds`, `process_max_fds`
|
|
- `process_start_time_seconds`
|
|
- `nodejs_eventloop_lag_seconds` and the `nodejs_eventloop_lag_*` family
|
|
- `nodejs_active_handles`, `nodejs_active_requests`, `nodejs_active_resources`
|
|
(and their `_total` variants)
|
|
- `nodejs_heap_size_total_bytes`, `nodejs_heap_size_used_bytes`,
|
|
`nodejs_external_memory_bytes`, `nodejs_heap_space_size_*_bytes`
|
|
- `nodejs_gc_duration_seconds`
|
|
- `nodejs_version_info`
|
|
|
|
The exact default-metric set is determined by `prom-client` and the Node.js
|
|
version, not by Etherpad.
|
|
|
|
### Opt-in scaling-dive metrics (`scalingDiveMetrics`)
|
|
|
|
A second, more detailed instrument set was added for the scaling investigation
|
|
(PR #7756). It is gated behind the `scalingDiveMetrics` setting, which defaults
|
|
to `false`:
|
|
|
|
```json
|
|
{
|
|
"scalingDiveMetrics": false
|
|
}
|
|
```
|
|
|
|
When the flag is off, these metrics are never registered and their recording
|
|
helpers short-circuit to no-ops, so production deployments pay nothing for the
|
|
instrumentation. When enabled, the following are added to the
|
|
`/stats/prometheus` output:
|
|
|
|
| Metric | Type | Labels | Meaning |
|
|
| --- | --- | --- | --- |
|
|
| `etherpad_changeset_apply_duration_seconds` | histogram | — | Time spent applying an incoming `USER_CHANGES` message on the server (apply path only; excludes fan-out to other clients). Buckets: 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 5 seconds. |
|
|
| `etherpad_socket_emits_total` | counter | `type` | Number of socket.io broadcast emits, bucketed by message type. |
|
|
| `etherpad_pad_users` | gauge | `padId` | Active users connected to each pad, keyed by pad id. |
|
|
|
|
**Cardinality caution.** The scaling-dive metrics carry high-cardinality
|
|
labels:
|
|
|
|
- `etherpad_pad_users` adds one time series **per active pad** (`padId`
|
|
label). On instances with many pads this can produce a large number of
|
|
series; stale labels are reset on each scrape so drained pads drop out.
|
|
- `etherpad_socket_emits_total` uses the `type` label. To keep cardinality
|
|
bounded, only a fixed allowlist of known message types is reported; any
|
|
other (or missing) type is rolled into a single `other` bucket, so a
|
|
misbehaving plugin or API caller cannot explode the label space.
|
|
|
|
Enable `scalingDiveMetrics` for targeted load-testing or capacity
|
|
investigations, not as a permanent production default.
|
|
|
|
## Scraping with Prometheus
|
|
|
|
Add a scrape job pointing at the `/stats/prometheus` endpoint, for example:
|
|
|
|
```yaml
|
|
scrape_configs:
|
|
- job_name: etherpad
|
|
metrics_path: /stats/prometheus
|
|
static_configs:
|
|
- targets: ['localhost:9001']
|
|
```
|
|
|
|
Make sure `enableMetrics` is `true` (the default) so the endpoint exists. If
|
|
your instance is reachable from untrusted networks, restrict access to
|
|
`/stats` and `/stats/prometheus` at your reverse proxy, since they expose
|
|
operational details about the deployment.
|