import type { Logger, LogLevel } from '../types/logger.js'; export type LogFormat = 'pretty' | 'json'; export interface DefaultLoggerOptions { level?: LogLevel | undefined; file?: string | undefined; /** * @deprecated Use `format: 'json'` instead. Kept for backward compat * with existing callers but has no effect on output — the `format` * option controls whether stderr receives pretty-printed or JSON lines. */ pretty?: boolean | undefined; /** Output format for stderr. `pretty` (colored, human-readable) or `json` (machine-parseable). Defaults to `WRONGSTACK_LOG_FORMAT` env var, falling back to `pretty`. */ format?: LogFormat | undefined; bindings?: Record; /** * When false, suppress stderr output entirely — only write to the log * file (if configured). Use this in TUI mode so plugin/library log * messages don't interleave with Ink's terminal rendering. * Default: true (stderr output is enabled). */ stderr?: boolean | undefined; /** * Rotate the log file once it exceeds this many bytes: the current file is * renamed to `.1` (replacing any previous one) and a fresh file * starts. Bounds total disk to ~2× this value. Default 10 MB. */ maxFileBytes?: number | undefined; } export declare class DefaultLogger implements Logger { /** How many file writes between rotation size checks (statSync is not free). */ private static readonly ROTATE_CHECK_EVERY; private static readonly MAX_PENDING_FILE_WRITES; private static readonly MAX_PENDING_FILE_BYTES; level: LogLevel; private file?; private bindings; private format; private stderr; private maxFileBytes; private writesSinceRotateCheck; /** * Serialized async tail for file writes. Every appendFile (and any * chained rotation) is awaited through this promise so file I/O * never overlaps itself — preserving the per-line ordering the * sync version had, but without blocking the caller thread. Any * rejection is swallowed (`catch(() => {})`) because logging must * never crash the host. * * Children share the parent's tail: `child.tail === parent.tail` * for the lifetime of the chain. Read/write access goes through * `_tail` so that, when a child has been wired to a parent, both * `enqueueRotate` and `log` always observe the parent's current tail * rather than a stale snapshot taken at `child()` time. */ private tail; private parent; private pendingFileWrites; private pendingFileBytes; private get root(); /** * Resolve the current tail. For the root logger this is the field; * for a child logger we always read through the parent so that a * child's appends land on the parent's most recent tail, and a * parent's `flush()` waits for everything the child chained. */ private get _tail(); private set _tail(value); constructor(opts?: DefaultLoggerOptions); error(msg: string, ctx?: unknown): void; warn(msg: string, ctx?: unknown): void; info(msg: string, ctx?: unknown): void; debug(msg: string, ctx?: unknown): void; trace(msg: string, ctx?: unknown): void; child(bindings: Record): Logger; /** * Wait until all queued file writes (and any pending rotation) have * completed. `log()` is fire-and-forget by design — the caller never * blocks on disk — so tests, shutdown handlers, and processes that * need a deterministic "everything is on disk now" guarantee should * `await logger.flush()` before reading the file or exiting. */ flush(): Promise; /** * Size-based rotation: when the file outgrows `maxFileBytes`, rename it to * `.1` (dropping the previous `.1`) so the live file restarts empty. * Checked on the first write and every ROTATE_CHECK_EVERY writes after. * Best-effort: a rename can fail on Windows while another process holds * the file — the next check retries. Multiple processes appending to the * same log all run this check; whoever crosses the threshold first wins. * * Async: the rotation runs on the file-write tail (so its writes don't * interleave with the next append), and the caller never blocks on a * statSync / renameSync syscall on the hot log path. */ private enqueueRotate; private log; } /** * A logger that silently discards all messages. Used during boot before * the real logger is configured, and in test contexts where logging * would be noise. */ export declare const noOpLogger: Logger; //# sourceMappingURL=logger.d.ts.map