import { transports } from 'winston'; import type { TransformableInfo } from 'logform'; /** * ChunkingConsoleTransport - a winston Console transport that SPLITS an oversized record into * several complete records instead of letting GCP silently drop it. * * WHY A TRANSPORT, not the WinstonLogger wrapper — two reasons, both decisive: * * 1. COVERAGE. WinstonFactoryBase sets `handleExceptions: true` / `handleRejections: true`, and * those lines are emitted by winston itself, bypassing WinstonLogger entirely. An uncaught * exception carrying a huge stack trace is exactly the log you cannot afford to lose, so the * guard has to sit below the wrapper. * 2. EXACT MEASUREMENT. A transport runs AFTER the format chain, so `info[MESSAGE]` is the fully * rendered line — envelope and all (severity, svcName, requestId, tenantId, the `api` tag). We * measure the real thing rather than estimating the caller's contribution and hoping. * * WHY IT RE-SERIALIZES rather than slicing `info[MESSAGE]`: a fragment of a JSON line is not valid * JSON, so the logging agent would file each piece as an unparsed `textPayload` and every structured * field would be lost. Each emitted piece must be a COMPLETE, parseable record — so we chunk the * oversized FIELDS and rebuild N records, each tagged with a shared {@link LogChunkInfo}. * * GCP-ONLY: wired in by WinstonGcpFactory. WinstonConsoleFactory keeps a plain Console transport — * a dev terminal has no size limit and splitting there would only hurt readability. * * The common case is untouched: a record within budget goes straight to `super.log` and is * byte-identical to what it was before this class existed. */ export declare class ChunkingConsoleTransport extends transports.Console { private readonly budgetBytes; constructor(budgetBytes?: number); log(info: TransformableInfo, callback: () => void): void; /** * Hand one finished record to the real Console transport. winston types `log` as optional on the * base, so we resolve it once here rather than sprinkling `?.` at the call sites — and if it were * ever truly absent we still fire the callback, because swallowing it would hang the logger. */ private writeThrough; /** Split the oversized record's fields and emit one complete record per piece. */ private logChunked; /** * Rebuild one complete record: every original field, with `message`/`errStack` replaced by this * piece and a `logChunk` tag added, re-serialized exactly the way format.json() would (same * safe-stable-stringify, so circular refs stay "[Circular]"). */ private buildRecord; /** The fully-rendered line the format chain produced (what a transport writes). */ private rendered; }