feat: add verbose/trace output for API latency debugging (-v to -vvvv)#56
feat: add verbose/trace output for API latency debugging (-v to -vvvv)#56gnapse merged 10 commits intoDoist:mainfrom
Conversation
Add a verbose logger with 4 levels (-v to -vvvv) for debugging API latency and CLI behavior. Output goes to stderr with timestamped [td:info/detail/debug/trace] prefixes. Supports TD_VERBOSE env var. Levels: -v (1) INFO : commands, endpoints, response status + timing -vv (2) DETAIL : request params, response metadata, pagination -vvv (3) DEBUG : ref resolution, HTTP headers, rate-limit info -vvvv (4) TRACE : full headers, body sizes, connection details Related to Doist#40 and customer support ticket #916983. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Register -v/--verbose as a Commander option (stackable: -v to -vvvv) and initialize the verbose logger before command parsing. Also disable the loading spinner when verbose mode is active, since spinner animations conflict with stderr diagnostic output. Related to Doist#40 and customer support ticket #916983. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add timing and verbose logging to the TodoistApi Proxy wrapper: - Log every SDK API method call with params at -v level - Log response duration_ms, result counts, pagination at -v level - Log full request params at -vv level - Log rate-limit and x-request-id headers at -vvv level - Log all response headers at -vvvv level Also instrument executeSyncCommand() with request/response logging including HTTP status, timing, and header inspection. Related to Doist#40 and customer support ticket #916983. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a verbose-aware fetch wrapper (verboseFetch) to the logger module that logs request/response details at all 4 verbosity levels: -v method + URL path + status + duration_ms -vv full URL, request body size, content-length -vvv rate-limit headers, x-request-id, cf-ray -vvvv all request/response headers (auth token redacted) Replace all direct fetch() calls across the API layer: - core.ts (executeSyncCommand) - workspaces.ts, stats.ts, reminders.ts, filters.ts - notifications.ts, uploads.ts, user-settings.ts This ensures every HTTP call made by `td` is visible in verbose mode, making it easy to diagnose API latency and capture diagnostics for support tickets. Related to Doist#40 and customer support ticket #916983. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ging Add verbose logging to refs.ts: - Log resolution strategy (direct ID lookup vs name search) - Log candidate counts, match types (exact/partial), results - Log auto-retry when raw ID fallback is triggered Add verbose logging to pagination.ts: - Log each page fetch with page number, cursor, page size - Log per-page timing (duration_ms) and result counts - Log pagination summary (total results, pages fetched, has_more) All logging at -vv (DETAIL) and -vvv (DEBUG) levels, helping to diagnose whether latency is in individual API calls or pagination. Related to Doist#40 and customer support ticket #916983. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update the agent skill content to document the new -v/--verbose global option, keeping it in sync with the CLI. Related to Doist#40 and customer support ticket #916983. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensure verbose output at all levels (-v to -vvvv) is safe to share in support tickets and public gists: - refs.ts: remove entity names (task content, project names) from debug logs; log only IDs and counts - logger.ts verboseFetch: log request body keys instead of raw content at TRACE level (body may contain user data in sync commands) - core.ts API proxy: redact 'query' and 'content' params to show only character length (e.g., "[16 chars]") - logger.ts: convert Verbosity enum to const object (biome lint) This allows users to capture -vvvv trace output and share it with support without exposing private task/project data. Related to Doist#40 and customer support ticket #916983. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the per-file verboseFetch() approach with a global fetch patch that activates when verbose mode is enabled. This captures HTTP-level details (status codes, timing, rate-limit headers, x-request-id) for ALL fetch calls including those made internally by @doist/todoist-api-typescript SDK. Previously, SDK-internal HTTP calls were invisible to verbose output. Now every HTTP request shows: -v method, URL path, status, duration_ms -vv full URL, body size, content-length -vvv rate-limit headers, x-request-id, cf-ray -vvvv all headers (auth redacted), body keys Remove verboseFetch() and its imports — no longer needed since the global patch covers all call sites uniformly. Related to Doist#40 and customer support ticket #916983. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gnapse
left a comment
There was a problem hiding this comment.
Thanks for putting this together. The verbose/trace idea could be useful for debugging latency, and the global fetch patch approach is right.
My main feedback: I think the PR does more than it needs to. The globalThis.fetch wrapper in logger.ts already captures timing, status, headers, and rate-limit info for every HTTP call the CLI makes. That single patch covers the stated goal ("diagnosing API latency") without touching any business logic.
But on top of that, the PR also manually instruments core.ts (+71 lines), pagination.ts (+28 lines), and refs.ts (+21 lines) with getLogger() calls — which largely duplicate what the fetch wrapper already logs. For example, the Proxy logging in core.ts that logs api.getTasks() with timing is restating what the fetch wrapper already reports as GET /rest/v2/tasks with the same duration_ms.
I'd suggest trimming this down to:
logger.ts— the Logger class + global fetch patch (the core of your PR, keep it)index.ts— register the--verboseflag, callinitializeLogger()spinner.ts— disable spinner when verbosecontent.ts— document the flag
And drop the changes to core.ts, pagination.ts, and refs.ts entirely. That gets us from +401/-5 across 7 files down to ~215 lines across 4 files, with zero changes to business logic, and the same user-facing functionality.
What do you think?
…refs.ts Drop verbose logging from business logic files — the globalThis.fetch patch in logger.ts already captures timing, status, and headers for every HTTP call, making these per-method logs redundant. Addresses review feedback on PR Doist#56. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gwpl
left a comment
There was a problem hiding this comment.
AI Assistant:
Thanks for the thoughtful review @gnapse! You're absolutely right — the globalThis.fetch patch already captures timing, status, and headers for every HTTP call, making the manual instrumentation in core.ts, pagination.ts, and refs.ts redundant.
I've pushed dd6e608 which reverts all changes to those 3 files, bringing the PR down to 4 files with zero changes to business logic:
logger.ts— Logger class + global fetch patch (core of the PR)index.ts—--verboseflag registration +initializeLogger()spinner.ts— disable spinner when verbosecontent.ts— document the flag
All 675 tests still pass. Appreciate the guidance on keeping it focused!
gnapse
left a comment
There was a problem hiding this comment.
Good. Thanks!
There's a pending issue: linting is not passing.
It's failing because of import sort order (Biome). Also, the eslint-disable comment doesn't do anything since this project uses Biome, not ESLint. And the import is actually used anyway so no disable needed.
Quick fix: npm run format
Or here's a patch if easier.
0001-fix-remove-useless-eslint-disable-and-fix-import-ord.patch
I tried contributing this commit myself, but the fork is not allowing push from me.
Move initializeLogger import to its alphabetically correct position after ./commands/* imports. ES module imports are hoisted, so order has no runtime effect — the initializeLogger() call site controls actual execution timing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Greg + AI Assistant: Apologies for the lint issue! I (Greg) am primarily a Rust developer, not a JavaScript/TypeScript one — we're putting this PR together with the help of an AI coding assistant, doing our best to deliver useful debug instrumentation for support ticket #916983 and give some code/inspiration along the way. The import ordering issue in (The CI runs for the new commit show Really appreciate the thoughtful review feedback, @gnapse. It's helping us iterate toward a clean, focused contribution together! |
|
Greg + AI Assistant: Thanks @gnapse! Good catch on both the import order and the useless Both issues are already addressed in commit 3d56f3e which was pushed ~24 minutes after your review — timing was just unfortunate:
Also thank you for trying to push the fix directly and for attaching the patch — really appreciate the collaborative spirit! |
Summary
Adds stackable verbose output (
-v,-vv,-vvv,-vvvv) to stderr for diagnosing API latency and behavior — especially useful for customer support tickets where users need to capture diagnostic traces.Closes #40
Related to customer support ticket #916983.
Verbosity levels
-vduration_ms)-vv-vvvx-request-id,cf-ray, reference resolution steps-vvvvAlso activatable via
TD_VERBOSE=1..4environment variable.Changes (14 files, +417 lines)
src/lib/logger.ts— new module:Loggerclass with 4 verbosity levels +verboseFetch()wrapper (drop-infetch()replacement that logs timing/headers)src/index.ts— register-v, --verboseglobal Commander option; initialize logger before parsingsrc/lib/spinner.ts— auto-disable spinner when verbose mode is activesrc/lib/api/core.ts— instrument SDK Proxy wrapper with per-call timing +executeSyncCommand()loggingsrc/lib/api/{workspaces,stats,reminders,filters,notifications,uploads,user-settings}.ts— replacefetch()→verboseFetch()in all 7 direct-fetch sitessrc/lib/refs.ts— log reference resolution strategy (ID lookup vs name search), match resultssrc/lib/pagination.ts— log per-page cursor progression and timingsrc/lib/skills/content.ts— document new flag in agent skill referenceExample output
All output goes to stderr with
[td:info/detail/debug/trace]prefixes — never pollutes stdout data pipes.Test plan
td --helpshows the new-v, --verboseoption-v,-vv,-vvv,-vvvvflags produce expected verbosity levelsTD_VERBOSE=2env var activates level 2🤖 Generated with Claude Code