# console-sink ## Purpose `ConsoleSink` is the human-readable terminal output sink for `@suaveplan/logger`. It formats each `LogRecord` into a single coloured, prefixed line and dispatches it to the appropriate `console` method (`console.debug`, `console.info`, `console.warn`, or `console.error`) so that log output appears at the correct severity level in browser DevTools and Node.js terminals alike. The sink is intentionally synchronous — `write` returns `void`, not `Promise` — because `console.*` is itself synchronous and any async wrapper would introduce misleading latency for a purely I/O-synchronous operation. ## Features - ANSI colour codes per log level: cyan for `debug`, green for `info`, yellow for `warn`, red for `error` - Optional ISO timestamp prefix, dimmed for contrast in colour mode - Optional `#tag` rendering when the log record carries `ctx.__tags` - Optional compact JSON metadata block printed below the message line - All formatting options can be toggled at construction time or by mutating public fields after construction - Delegates to the correct `console` method for each log level, preserving browser DevTools severity grouping - No external dependencies beyond the `Sink` interface and `LogRecord` types ## Usage: Basic Example ```ts import { ConsoleSink } from "@suaveplan/logger/sink"; const sink = new ConsoleSink(); // colors + timestamp enabled by default sink.write({ ts: new Date().toISOString(), level: "info", msg: "Server started", ctx: {}, }); // Output: [2024-01-01T00:00:00.000Z] [INFO] Server started ``` ## Usage: Advanced Example ```ts import { ConsoleSink } from "@suaveplan/logger/sink"; import { ConsoleLogger } from "@suaveplan/logger/console"; // Plain text for CI environments (no ANSI codes in log files) const sink = new ConsoleSink({ colors: false, timestamp: true, includeMetadata: true, includeTags: true, }); const logger = new ConsoleLogger({ sink }); logger.info("Request completed", { __tags: ["http", "perf"], duration: 42, status: 200, }); // Output: // [2024-01-01T00:00:00.000Z] [INFO] [#http #perf] Request completed // { // "__tags": ["http", "perf"], // "duration": 42, // "status": 200 // } ``` ## API Reference ### `class ConsoleSink implements Sink` **Constructor**: `new ConsoleSink(options?: ConsoleSinkOptions)` All options are also exposed as mutable public fields so they can be toggled after construction (e.g., to disable colours when a terminal is detected as non-interactive). | Option / Field | Type | Default | Description | |---|---|---|---| | `colors` | `boolean` | `true` | Wrap level and timestamp tokens in ANSI colour escapes | | `timestamp` | `boolean` | `true` | Prefix each line with the record's `ts` value | | `includeMetadata` | `boolean` | `false` | Append `ctx` as a formatted JSON block below the message | | `includeTags` | `boolean` | `true` | Inline `ctx.__tags` values as `#tag` tokens | **Methods** - `write(record: LogRecord): void` — Format and print the record synchronously. Never throws; `console.*` errors (which are vanishingly rare) surface as uncaught exceptions in the host environment. ## Implementation Notes ANSI escape codes are defined as a small static map keyed by `LogLevel` plus `"reset"` and `"dim"` sentinels. The formatter builds a `parts: string[]` array and joins once at the end to minimise string concatenation allocations per record. The sink checks `console[method]` at call time rather than caching the reference at construction, which means it respects any `console` mocking that test frameworks install. This is deliberate — `ConsoleSink` is commonly used in test environments where `console.error` is wrapped to assert that no unexpected errors are logged. Colour mode does not auto-detect `process.stdout.isTTY`; that decision is left to the caller (typically the factory or the logger bootstrap) so the sink itself remains environment-agnostic and testable without process environment manipulation.