Skip to content

log

Tagged, leveled logging for every runtime - the one logger the whole monorepo shares.

logger resolves a tagged Logger via a LoggerFactory. The factory starts as a synchronous console sink so this module never uses top-level await (that left importers with a null namespace mid-load in browser bundles). A memoized async chain then upgrades to consola when it is available. LogLevel filtering runs through shouldEmit in the consola reporter or in per-level wrappers on the console fallbacks.

Sink selection chains two factories with nullish coalescing (first match wins):

  1. createConsolaLoggerFactory when consola resolves and LOG_CONSOLA_DISABLED is not truthy.
  2. createConsoleLoggerFactory everywhere else (also the sync bootstrap before that promise settles).

The console fallback writes formatted lines to process.stderr when it is available (Bun inspect per argument when LOG_BUN_CONSOLE_DISABLED is unset, otherwise node:util formatWithOptions), or delegates to global console.* when stderr or node:util is unavailable. Browser hosts omit the LEVEL text prefix (devtools show severity) and keep only the [name] tag.

Env toggles: LOG_LEVEL (read per call), LOG_CONSOLA_DISABLED / LOG_BUN_CONSOLE_DISABLED (read once during factory init).

Browser-safe: process / Bun / window / document are all reached through globalThis and guarded, consola loads lazily, and node:util is imported ONLY on a host that has process.stderr - never in a browser, where the specifier is unresolvable - so the module works in any runtime. Consola is an optional peer; the module loads fine without it.