feat(debug): add capture trace on error admin option#663
Conversation
Add a persisted admin toggle that forces debug trace capture and persistence for a request whenever it writes to the inference error log or triggers a provider cooldown, even when global/per-key debug tracing is disabled. Surfaced on both the Config and Debug pages.
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
| export function setCurrentRequestId(requestId: string): void { | ||
| const store = storage.getStore(); | ||
| if (store) store.requestId = requestId; | ||
| } |
There was a problem hiding this comment.
Suggestion: Mutating the shared RequestContext store object directly is unsafe, as other consumers may hold references to it. Create a shallow copy with the new requestId and re-enter the AsyncLocalStorage context using storage.enterWith() to ensure the update is isolated to the current execution chain. [possible issue, importance: 8]
| export function setCurrentRequestId(requestId: string): void { | |
| const store = storage.getStore(); | |
| if (store) store.requestId = requestId; | |
| } | |
| export function setCurrentRequestId(requestId: string): void { | |
| const store = storage.getStore(); | |
| if (store) { | |
| storage.enterWith({ ...store, requestId }); | |
| } | |
| } |
| isCaptureEnabled(): boolean { | ||
| return this.isEnabledForKey(getCurrentKeyName() ?? null); | ||
| // Capture-on-error mode buffers every request so a trace exists to persist | ||
| // if the request later errors or triggers a cooldown. | ||
| return this.captureOnError || this.isEnabledForKey(getCurrentKeyName() ?? null); | ||
| } |
There was a problem hiding this comment.
Suggestion: When captureOnError is enabled, isCaptureEnabled() returns true for every request, causing all requests to be buffered in pendingLogs until flush. For high-throughput deployments this can lead to unbounded memory growth if many requests succeed and are discarded. Consider adding a cap on the number of pending logs or a TTL-based eviction for buffered traces in capture-on-error mode. [general, importance: 7]
| isCaptureEnabled(): boolean { | |
| return this.isEnabledForKey(getCurrentKeyName() ?? null); | |
| // Capture-on-error mode buffers every request so a trace exists to persist | |
| // if the request later errors or triggers a cooldown. | |
| return this.captureOnError || this.isEnabledForKey(getCurrentKeyName() ?? null); | |
| } | |
| isCaptureEnabled(): boolean { | |
| // Capture-on-error mode buffers every request so a trace exists to persist | |
| // if the request later errors or triggers a cooldown. | |
| if (this.captureOnError) { | |
| // Guard against unbounded memory growth in high-throughput scenarios. | |
| if (this.pendingLogs.size >= this.maxPendingCaptureOnErrorLogs) { | |
| logger.warn('Capture-on-error pending log buffer full; skipping capture'); | |
| return false; | |
| } | |
| return true; | |
| } | |
| return this.isEnabledForKey(getCurrentKeyName() ?? null); | |
| } |
Replace the async-local store via enterWith instead of mutating the existing object in place, so other holders of a reference to the prior store aren't affected. Addresses PR review feedback.
User description
Summary
Adds a persisted admin toggle, Capture Trace on Error, that forces debug trace capture/persistence for a request whenever it writes to the inference error log or triggers a provider cooldown — even when global/per-key debug tracing is otherwise disabled.
Behavior
DebugManagerbuffers a trace for every request in memory, but only persists it if the request:UsageStorageService.saveError), orCooldownManager.markProviderFailure, including stall cooldowns).systemSettingstable (debug.captureOnError), loaded intoDebugManagerat startup, and mirrored live on PATCH.Backend changes
services/request-context.ts— addedrequestIdto the async-local request context.services/debug-manager.ts—captureOnErrorflag, broadenedisCaptureEnabled(),forcePersistflag onDebugLogRecord,markForcePersist().services/usage-storage.ts—saveError()triggers force-persist.services/cooldown-manager.ts—markProviderFailure()triggers force-persist via request context.db/config-repository.ts/routes/management/config.ts— persisted setting +GET/PATCH /v0/management/config/capture-trace-on-error.index.ts— loads the persisted setting intoDebugManagerat startup.Frontend changes
lib/api.ts— client methods for the new endpoint.pages/Config.tsx/pages/Debug.tsx— toggle UI.Testing
bun run typecheck— passes across all workspaces.bun run test:force-all— 206 test files, 2306 tests passed.Description
Add persisted admin toggle
capture-trace-on-errorto force trace persistence on errors or cooldownsIntegrate
forcePersistflag inDebugManagertriggered byUsageStorageServiceandCooldownManagerAdd
requestIdto async-local request context for trace correlationAdd API endpoints and frontend UI on Config and Debug pages for the new setting