diff --git a/advanced/metrics.mdx b/advanced/metrics.mdx index 693c1e8b..929e297a 100644 --- a/advanced/metrics.mdx +++ b/advanced/metrics.mdx @@ -77,6 +77,10 @@ All metrics are prefixed with `wa_` and emitted at the same boundaries as the ma | `wa_recv_total` | `outcome` = `decrypted`, `duplicate`, `undecryptable`, `skmsg` | Inbound messages by decrypt outcome | | `wa_send_total` | `kind` = `dm`, `group`, `status` | Outgoing send attempts by kind | | `wa_retry_receipt_total` | `reason` | Retry receipts sent, by reason | +| `wa_high_retry_total` | `reason` | Retry receipts sent at the high-retry watermark (count ≥ MAX), by reason | +| `wa_retry_unknown_device_total` | `sender_type` = `primary`, `companion` | Retries from a device not in the registry, by sender type | +| `wa_retry_refused_total` | — | Retries refused at the MAX_RETRY loop guard | +| `wa_base_key_collision_total` | — | Base-key collisions that forced a fresh session | | `wa_iq_total` | `result` = `ok`, `timeout`, `error` | IQ requests by result | | `wa_reconnect_total` | — | Reconnect attempts | | `wa_stream_error_total` | — | Stream errors received | diff --git a/advanced/observability.mdx b/advanced/observability.mdx index 39ae7a5b..1cca4ef4 100644 --- a/advanced/observability.mdx +++ b/advanced/observability.mdx @@ -96,7 +96,7 @@ Spans are grouped under a stable `wa..` naming scheme so you can filte | `wa.pair.*` | QR code and pair code authentication | | `wa.media.*` | Upload, download, history sync, sticker packs, media conn refresh | | `wa.receipt.*` | Receipt processing (delivered, read, played) | -| `wa.retry.*` | Retry receipt handling | +| `wa.retry.*` | Retry receipt handling; `wa.retry.handle_receipt` records a `count` field (retry depth) so storm depth is aggregable per sender | | `wa.pdo.*` | Peer Data Operations (message recovery via primary device) | | `wa.notif.*` | Notification dispatch (group, devices, chatstate, identity change, privacy token) | | `wa.session.*` | Signal session establishment and crypto | diff --git a/changelog/2026-06-17-retry-warn-levels-and-telemetry.mdx b/changelog/2026-06-17-retry-warn-levels-and-telemetry.mdx new file mode 100644 index 00000000..6689de0d --- /dev/null +++ b/changelog/2026-06-17-retry-warn-levels-and-telemetry.mdx @@ -0,0 +1,34 @@ +--- +title: "June 17, 2026 — Retry log-level parity and observability counters" +description: "Four new wa_retry_* / wa_base_key_collision_total counters, a retry count field on the handle_receipt span, and two WARN→debug/info corrections that match WA Web's own log levels." +--- + +## Observability + +**Retry-flow observability counters and WA Web log-level parity ([#887](https://github.com/oxidezap/whatsapp-rust/pull/887))** + +### New metrics counters + +Four new low-cardinality, PII-safe counters are now emitted on the retry flow when the `metrics` feature is enabled. All four compile to inlined no-ops without the feature. + +| Counter | Labels | Emitted when | +|---------|--------|--------------| +| `wa_high_retry_total` | `reason` | A retry receipt is sent at the high-retry watermark (count ≥ MAX). Mirrors WA Web's `MessageHighRetryCount` WAM event (id 3132). | +| `wa_retry_unknown_device_total` | `sender_type` = `primary`, `companion` | A retry arrives from a device not in the registry. Mirrors WA Web's `MdRetryFromUnknownDevice` WAM event (id 2178). | +| `wa_retry_refused_total` | — | A retry is refused at the MAX_RETRY loop guard. Turns a chronically thrashing peer into an aggregate health signal instead of requiring log scraping. | +| `wa_base_key_collision_total` | — | A base-key collision forced a fresh session. | + +### Tracing span field + +`wa.retry.handle_receipt` now records a `count` field (the retry depth for that receipt). This makes retry storm depth aggregable per sender even when the MAX_RETRY cap causes an early return. + +### Log-level corrections + +Two retry-path `warn!` calls that fired for benign, remote-driven, fully-handled conditions are now emitted at levels matching WA Web's own `WALogger.LOG` (informational): + +- **"Refusing retry #N … exceeds max attempts"**: `warn!` → `debug!`. WA Web's `WAWebHandleRetryRequest` uses `LOG` (level 2) for this refusal and reserves `WARN` for real errors (no-requester, device-not-found). The mirror receive-side capped-retry path in `message/retry.rs` already logged at `debug!`. +- **"Base key collision detected …"**: `warn!` → `info!`. WA Web's `WAWebUpdateLocalSignalSession` uses `LOG` for the same-base-key session delete, and the three sibling branches of `update_local_signal_session` already log at `info`. + +Both lines now also include the `message_id` so collisions are correlatable to a specific message during a retry storm. + +**No behavior change.** Every modification is a log level, an added log field, a counter increment, or a span field. The retry logic (cap value, base-key save/compare/delete, recovery path) is verbatim parity with the WA Web oracle and is untouched. diff --git a/docs.json b/docs.json index 46f7bd29..ea8ff10e 100644 --- a/docs.json +++ b/docs.json @@ -138,6 +138,7 @@ "group": "Changelog", "pages": [ "changelog/overview", + "changelog/2026-06-17-retry-warn-levels-and-telemetry", "changelog/2026-06-15-token-tiny-map", "changelog/2026-06-14-drop-moka-portable-cache", "changelog/2026-06-12-binary-size-ci",