Skip to content

Replace console.warn/log in sync hot paths with structured logging #54

@studert

Description

@studert

Problem

Several production code paths still call console.warn / console.log directly. In a Vercel Functions deployment these end up in the runtime log stream, but as unstructured strings — not joinable with sync run ids, not filterable by source type, and easy to lose in volume. We should standardize on a small structured-logger helper before more code copies the pattern.

Evidence

Production-path console calls:

  • src/lib/sync/sources/anthropic-workspace.ts:237,258console.warn on per-workspace cost-sync edge cases.
  • src/lib/anthropic-keys.ts:49console.warn for missing keys.
  • src/lib/db/seed.ts:34console.log printing the seeded admin credentials to stdout (only runs locally on pnpm db:seed, but worth tightening — see acceptance criteria).
  • src/actions/copilot.ts:72, src/app/api/invoices/ingest/route.ts:297, src/app/api/profile/route.ts:97console.error on failure paths. These are acceptable as fallbacks but should still get the structured wrapper.

Acceptable / out of scope:

  • src/lib/db/baseline-migration.ts:47,65,66 — dev migration helper, runs once.
  • Test files and scripts under scripts/.

Proposed approach

  1. Create src/lib/logger.ts with a tiny structured-logger wrapper. Keep it dependency-free (no Pino, no Winston) — just:
    type Level = \"debug\" | \"info\" | \"warn\" | \"error\";
    export function log(level: Level, message: string, fields?: Record<string, unknown>) {
      const payload = { level, message, ts: new Date().toISOString(), ...fields };
      // Vercel parses JSON in console output as structured logs
      (level === \"error\" ? console.error : console.log)(JSON.stringify(payload));
    }
  2. Replace each console.warn / console.log listed above with log(\"warn\", \"...\", { sourceType, runId, userId, … }).
  3. Replace existing console.error calls in the listed action/route files with log(\"error\", \"...\", { error: serializeError(err) }).
  4. For src/lib/db/seed.ts:34: stop logging the seeded password. Print only the email and a note that the password was set from the env var or written to the screen exactly once on first run, then never again.
  5. Add a Vitest unit test that captures console.log and asserts JSON shape.
  6. Document the helper in CLAUDE.md under "Code Style" as the canonical way to log.

Acceptance criteria

  • src/lib/logger.ts exists with log(level, message, fields?).
  • All listed console.warn / console.log / console.error sites in production paths use the helper.
  • src/lib/db/seed.ts no longer prints the seeded password to stdout.
  • CLAUDE.md mentions the helper.
  • pnpm lint && pnpm typecheck && pnpm test pass.

Verification

  1. Run a sync that triggers the warn paths (e.g. anthropic-workspace sync against a workspace with no costs) and grep the output for \"level\":\"warn\".
  2. Run pnpm db:seed → stdout shows the email but not the password.
  3. Search the repo for console\\.(log|warn|error) and confirm no new matches outside src/lib/logger.ts, tests, and explicitly justified exceptions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:syncSync framework / cron / ingestionpriority:lowNice to havetech-debtCode quality, refactor, debt

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions