/** * Terminal-first logger with two renderings and one automatic decision. * * Two knobs, never confusing: format = how lines render, time = whether * lines carry time. Each defaults sensibly and independently. * * Format — LOG_FORMAT=human|record, or setLogFormat(). Default by TTY * detection on the sink: a TTY gets human (symbols, color, a line meant * for eyes), anything else gets record (level words, plain text, a line * meant for a file read later). Detection happens on the stream actually * written to (stderr), never a sibling stream. * * Time — LOG_TIME=1|0, or setLogTime(). Default: on in Node record mode, * off everywhere else (human eyes don't need stamps; browser and Worker * consoles stamp lines themselves). Record time opens the line with UTC * RFC3339; human time prefixes a dim local HH:MM:SS (a human knows * today's date). * * The record line with time on, identical across go-utils and py-utils by * design: * 2026-08-07T12:34:56Z WARN [scope] message * UTC RFC3339 seconds precision · level word padded to 5 · scope brackets * only when scoped · no color, no symbols. Grep WARN, not ⚠. * * Sinks * Node/Bun/Deno: every level writes to stderr through console.error, so * stdout stays clean for data and cli/live's console routing keeps log * lines above an active region. * Browser: level-mapped console methods (debug/info/warn/error), human. * Workers: level-mapped console methods, record. * * Levels vs verbs * Levels filter: silent < error < warn < info < debug < trace. An unknown * LOG_LEVEL is a misconfiguration and throws Panic. * Verbs express outcome and are renderings, never levels: * error ⨯ fail ⨯ (error) · warn ⚠ (warn) · info · success ✓ · wait ○ · * ready ▶ · step • (info) · debug ◦ (debug) · trace » (trace). * In record mode a verb renders as its level word. * * Scopes * log.scope('api') returns a child whose lines carry [api]; scopes nest * and join: log.scope('api').scope('auth') → [api auth]. A scoped logger * resolves its threshold from {SCOPE}_LOG_LEVEL (upper-cased, joined and * sanitized to A-Z0-9_: API_AUTH_LOG_LEVEL, then API_LOG_LEVEL), falling * back to setLogLevel(), then LOG_LEVEL, then info — read live, so one * subsystem can be silenced or opened up without touching code. * * Config is env plus three runtime setters — setLogLevel(), setLogFormat(), * setLogTime(). No handlers, no formatters, no init. NO_COLOR / * FORCE_COLOR override color within human mode. Unknown values of any * knob throw Panic. All internal memory is bounded. * * Siblings: go-utils and py-utils implement the same doctrine in their own * idioms; the record line format is identical by design. */ export type LogFormat = "human" | "record"; /** Force human or record rendering at runtime. Wins over LOG_FORMAT and auto-detection. */ export declare function setLogFormat(format: LogFormat): void; /** Force time prefixes on or off at runtime. Wins over LOG_TIME and the defaults. */ export declare function setLogTime(on: boolean): void; declare const LEVELS: { readonly silent: 0; readonly error: 1; readonly warn: 2; readonly info: 3; readonly debug: 4; readonly trace: 5; }; export type LogLevel = keyof typeof LEVELS; /** Set the global log level at runtime. Wins over LOG_LEVEL; per-scope env vars still win over this. */ export declare function setLogLevel(level: LogLevel): void; export interface Logger { error(...messages: unknown[]): void; fail(...messages: unknown[]): void; warn(...messages: unknown[]): void; /** warn() that fires once per distinct message for the process lifetime. */ warnOnce(...messages: unknown[]): void; info(...messages: unknown[]): void; success(...messages: unknown[]): void; wait(...messages: unknown[]): void; ready(...messages: unknown[]): void; /** Indented sub-step bullet under a wait/ready line. */ step(...messages: unknown[]): void; debug(...messages: unknown[]): void; trace(...messages: unknown[]): void; /** Start a duration measurement; timeEnd() reports it at trace level. */ time(label: string): void; timeEnd(label: string): void; /** Child logger: lines carry [name], level reads {NAME}_LOG_LEVEL first. */ scope(name: string): Logger; } export declare const error: (...messages: unknown[]) => void; export declare const fail: (...messages: unknown[]) => void; export declare const warn: (...messages: unknown[]) => void; export declare const warnOnce: (...messages: unknown[]) => void; export declare const info: (...messages: unknown[]) => void; export declare const success: (...messages: unknown[]) => void; export declare const wait: (...messages: unknown[]) => void; export declare const ready: (...messages: unknown[]) => void; export declare const step: (...messages: unknown[]) => void; export declare const debug: (...messages: unknown[]) => void; export declare const trace: (...messages: unknown[]) => void; export declare const time: (label: string) => void; export declare const timeEnd: (label: string) => void; export declare const scope: (name: string) => Logger; /** The root logger plus its runtime knobs, for namespace-style consumers. */ export declare const log: Logger & { setLogLevel: typeof setLogLevel; setLogFormat: typeof setLogFormat; setLogTime: typeof setLogTime; }; export {}; //# sourceMappingURL=log.d.ts.map