Files
vercel__workflow/packages/utils/src/debug-log.ts
Pranay Prakash ffc58078d0 Stop logging on healthy workflow execution (#3878)
A successful run printed several lines that described the runtime working
correctly. Most of it was fallout from defaulting the events transport to
WebSockets (#3702): three breadcrumbs written while the transport was opt-in
became default-path output, because each one reported a choice the caller no
longer makes.

- `world-vercel: using ws events transport (…)` ran once per cold start on
  every deployment, naming the transport it was always going to use.
- The `projectConfig` proxy fallback warned once per process. That World cannot
  hold a socket, so with WS on by default every CLI command and the
  observability app warned about a fallback nobody asked for and nobody can act
  on. Debug-gated and reworded from "requested but" to "unavailable for".
- The `max_duration` / `auth_expiry` drain notice is routine: the transport
  reconnects from the close that follows and no write is lost.

Swept for the same shape elsewhere:

- `world-local`'s queue-concurrency notice fired per message once a fan-out
  exceeded the limit — the semaphore doing its job.
- `@workflow/world`'s active-run recovery line printed on every dev-server
  restart with work in flight. The re-enqueue *failure* above it stays
  unconditional; that one leaves a run unresumed.
- The port-detection diagnostics in `@workflow/utils` keyed off
  `NODE_ENV=development`, which is the only environment that reaches them, so
  the gate made them unconditional for their whole audience.

All of it moves behind `DEBUG=workflow:*` via a new `debugLog` in
`@workflow/utils`, joining world-vercel's existing `httpLog` and `logRetry`
output under one selector. Warnings and errors are untouched, so a run that
actually goes wrong is no quieter than before — the ws-transport tests that
assert failures are never silent still pass unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Co-Authored-By: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
2026-08-27 20:45:20 -07:00

37 lines
1.7 KiB
TypeScript

/**
* The `DEBUG` gate for diagnostic log lines emitted by the layers below
* `@workflow/core`.
*
* `@workflow/core` has a real logger (`packages/core/src/logger.ts`) whose
* `debug`/`info` levels are already gated this way. The packages under it —
* `@workflow/utils`, `@workflow/world`, `@workflow/world-local`,
* `@workflow/world-vercel` — carry no logger dependency, so a breadcrumb there
* is a bare `console.*` call: unconditional, and therefore in every user's
* function logs on a normal run. This is the gate those call sites use instead.
*
* Accepts the same selectors a namespaced logger would match for a line that
* has no namespace of its own: any `workflow:`-prefixed pattern, or `*`.
*/
export function isWorkflowDebugEnabled(): boolean {
// Read per call rather than captured at module load. A World is often
// constructed long after import (and a test sets `DEBUG` in `beforeEach`),
// so a module-scope constant answers for the wrong moment.
const debug = typeof process !== 'undefined' ? process.env.DEBUG : undefined;
if (typeof debug !== 'string') return false;
return debug.includes('workflow:') || debug === '*';
}
/**
* Emit a diagnostic line only under `DEBUG`.
*
* `console.debug` to match the rest of the SDK's debug output — core's logger,
* world-vercel's `httpLog` and `logRetry` — so one `DEBUG=workflow:*` collects
* all of it. Use this for anything a *successful* run would print; a genuine
* anomaly still belongs on `console.warn`/`console.error`, which stay
* unconditional so a broken run is never silent.
*/
export function debugLog(...args: unknown[]): void {
if (!isWorkflowDebugEnabled()) return;
console.debug(...args);
}