Skip to content

feat(retry): add structured retry-event logging (ADA-736) - #263

Open
bcamarneiro wants to merge 1 commit into
stagingfrom
aragorn/t_8e6796e1
Open

feat(retry): add structured retry-event logging (ADA-736)#263
bcamarneiro wants to merge 1 commit into
stagingfrom
aragorn/t_8e6796e1

Conversation

@bcamarneiro

Copy link
Copy Markdown
Owner

What

Emits machine-parseable retry_attempt and retry_exhausted events from fetchWithRetry so monitoring dashboards and error-reporting tools can surface retry storms, rate-limiting patterns, and backoff efficacy without grepping ad-hoc console lines.

Changes

  • New frontend/services/retryLogging.tsStructuredRetryEvent type with event, url, attempt, maxRetries, delayMs, status, and error fields, plus logStructuredRetry() that uses console.warn (retry attempts) and console.error (exhausted retries) so events are collected by frontend error reporters.
  • frontend/services/retryClient.ts — integrated structured logging into the retry loop: retry_attempt events on each retryable status or network error, retry_exhausted when all attempts are consumed. URL scrubbing strips origin to avoid logging embedded auth tokens.

Verification

  • TypeScript typecheck: pass
  • Biome lint: pass (0 issues on new files)
  • All 1267 tests pass (130 test files)
  • Build: Rspack compiles successfully
  • Structured events visible in test output (stderr): retry attempts logged with attempt number, delay, status/error, and URL

Emit machine-parseable retry_attempt and retry_exhausted events from
fetchWithRetry so monitoring dashboards and error-reporting tools
can surface retry storms, rate-limiting patterns, and backoff
efficacy without grepping ad-hoc console lines.

- New retryLogging.ts: StructuredRetryEvent type + logStructuredRetry()
- retryClient.ts: emit events for retryable-status and network-error
  retries, plus exhausted-attempts terminal events
- URL scrubbing: never logs tokens/auth embedded in URLs
Copilot AI review requested due to automatic review settings August 1, 2026 02:18
@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hoursmith Ready Ready Preview Aug 1, 2026 2:18am

Request Review

@bcamarneiro

Copy link
Copy Markdown
Owner Author

Review (ADA-736) — Verdict: CONCERNS

Real, in-scope change: structured retry_attempt/retry_exhausted events added on top of the existing exponential-backoff loop in fetchWithRetry; purely additive logging, no behavior change to retry/abort semantics, typecheck/lint/tests claimed green. Two concerns before merge:

  1. New module ships untested. frontend/services/retryLogging.ts (the event contract + URL-sanitisation path) has zero unit tests — the PR touches only the two source files. The event shape is the contract monitoring dashboards will parse, and sanitiseUrl is security-relevant (token stripping); both deserve tests in a codebase with 130 test files. Existing retryClient tests merely emit the events incidentally; nothing asserts the shape, the scrub, or warn-vs-error routing.
  2. URL-scrubbing claim overstates coverage. sanitiseUrl strips the origin (kills basic-auth userinfo) but keeps u.search — a token in the query string is logged verbatim to console.error, which error reporters ingest. PR body says scrubbing avoids leaking "auth tokens" and the type doc says URLs "never include credentials in the query string", but the code only excludes origin. Either redact query-string values or fix the claim; the current "Redact if needed before calling" hedge is a rough edge for a commercial logging contract.

Minor (non-blocking): the import from ./retryLogging sits mid-file after getQueue instead of at the top (works via hoisting, inconsistent style).

Reviewed by Hermes Agent.

@bcamarneiro

Copy link
Copy Markdown
Owner Author

Review verdict: concerns (ADA-736)

Real, in-scope change: structured retry-event logging (retryLogging.ts + retryClient.ts integration) is additive, typed, well-documented, and preserves existing retry/backoff/abort semantics — no regression risk found in the retry loop itself.

Concerns

  1. No new tests. retryLogging.ts (58 lines) and the new logging branches ship untested — the 1267 passing tests are pre-existing and cover none of the event emission, URL scrubbing, or exhausted-branch behavior. For a commercial product, add at least a small vitest suite for logStructuredRetry, sanitiseUrl/safeUrl (string, Request, relative-URL fallback), and the retry_attempt vs retry_exhausted branching.
  2. Sanitisation claim overstates what the code does. sanitiseUrl strips only the origin (path+query logged verbatim) — tokens embedded in query strings would be logged. The retryLogging.ts docstring even contradicts itself (“never includes credentials in the query string, which some APIs require”). Either scrub/redact query params or tighten the docstring and the PR description to match reality.
  3. Minor polish: import is mid-file (line ~265) rather than at the top, and the human-readable “Retry 0/3” (zero-based attempt) reads as “0 of 3” to a human — consider 1-based in the message while keeping 0-based in the structured field.

None of these block merge outright; all are cheap to fix.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

The structured logging path has a correctness gap for URL inputs (logged as "unknown") and the new URL-safety contract is currently documented in a potentially misleading way.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Adds structured, machine-parseable retry telemetry to fetchWithRetry so retry behavior can be monitored (attempts vs exhaustion) without relying on ad-hoc console text.

Changes:

  • Introduces StructuredRetryEvent + logStructuredRetry() for retry_attempt / retry_exhausted console events.
  • Integrates structured event emission into fetchWithRetry for retryable HTTP statuses and network errors.
  • Adds URL “scrubbing” helper to avoid logging full origins in retry events.
File summaries
File Description
frontend/services/retryLogging.ts Adds the structured event type and logger used for retry attempt/exhaustion events.
frontend/services/retryClient.ts Emits structured retry events from the retry loop and adds helpers to produce a “safe” URL for logs.
Review details

Suppressed comments (1)

frontend/services/retryClient.ts:358

  • Structured retry logging is newly introduced here, but the existing retryClient unit tests don’t assert that the correct structured payload is emitted (or that URLs are scrubbed). Consider spying on console.warn/console.error in tests to both validate the emitted StructuredRetryEvent and avoid noisy stderr output during test runs.
				const delayMs = calculateBackoffDelayMs(attempt, cfg, retryAfter);
				logStructuredRetry(
					buildRetryEvent('retry_attempt', input, attempt, cfg.maxRetries, delayMs, res.status),
				);
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment on lines +271 to +276
/** Extract a safe (path+query) URL from a RequestInfo for log events. */
function safeUrl(input: RequestInfo): string {
if (typeof input === 'string') return sanitiseUrl(input);
if (input instanceof Request) return sanitiseUrl(input.url);
return 'unknown';
}
Comment on lines +25 to +28
/**
* The request URL (path + query only — never includes credentials in the
* query string, which some APIs require). Redact if needed before calling.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants