import { type LogRecord, type LogSink, type Logger } from '@cat-factory/kernel'; /** * The field this exporter binds onto the logger it reports its OWN failures through, and * refuses to export. * * Without it the pipeline feeds itself: a failed POST logs a warning, the adapter fans that * warning back into this buffer, the next flush fails the same way, and a collector outage * becomes an ever-growing batch of lines about a collector outage. The warning still reaches * the LOCAL writer, which is where an operator whose collector is down can actually read it. */ export declare const SELF_LOG_FIELD = "otelLogExport"; /** Default lines per POST; also the size at which a full buffer triggers a send. */ export declare const DEFAULT_LOG_BATCH_SIZE = 128; export interface OtelLogExporterConfig { /** OTLP/HTTP base URL, e.g. `http://collector:4318` (`/v1/logs` is appended). */ endpoint: string; /** Extra headers merged onto every request (auth tokens, tenant ids, …). */ headers?: Record; /** OTLP resource `service.name`; defaults to `cat-factory`. */ serviceName?: string; /** Lines per POST; defaults to {@link DEFAULT_LOG_BATCH_SIZE}. */ maxBatchSize?: number; /** * Logger for this exporter's own swallowed failures. Bound with {@link SELF_LOG_FIELD}, so * those lines reach the local writer and are refused by the buffer (see the constant). */ logger?: Logger; /** Injectable fetch (tests); defaults to the global `fetch`. */ fetchImpl?: typeof fetch; } export declare class OtelLogExporter implements LogSink { private readonly logsEndpoint; private readonly headers; private readonly serviceName; private readonly maxBatchSize; private readonly logger?; private readonly fetchImpl; /** Lines accepted but not yet POSTed. Bounded by `maxBatchSize * MAX_QUEUED_BATCHES`. */ private buffer; /** Lines dropped by the bound above since the last time the drop was reported. */ private dropped; /** * The tail of the send chain. Sends are SERIALISED rather than issued concurrently, so a * batch-size trigger and a flush can never interleave two POSTs that both drained part of * the buffer. `flush()` awaiting this tail is also what lets a Worker's `waitUntil` cover a * send that started while the request was still being served. */ private inFlight; constructor(config: OtelLogExporterConfig); /** * Buffer one line, and start a send once a full batch has accumulated. Never throws and * never awaits: this runs inside `logger.info(…)`, so anything slower than an array push * would put the collector's latency on the caller's path. */ record(record: LogRecord): void; /** * Deliver everything buffered. Called on an interval by the Node facade and once per * invocation by the Worker; resolves once every send it started (and any already in flight) * has settled. Best-effort: it resolves rather than rejecting when delivery failed. */ flush(): Promise; /** * Queue a drain behind whatever is already sending, keeping POSTs strictly serial. * * The chain is TERMINATED here, and that catch is the port's `flush` obligation made * structural rather than merely intended. A rejection left on `this.inFlight` is not one bad * batch: every later `kick` chains onto the rejected tail and inherits it, so the exporter * would never deliver another line, `flush()` would reject forever, and on Node the * interval's `void flush()` would become an unhandled rejection that the process failure * guards answer by EXITING. Observability would have taken the deployment down. * * Nothing on the drain path is expected to throw (the mapping is total and `postOtlp` * swallows), so this catch should stay unreachable. It is here because "unreachable" is a * property of today's code, and the cost of being wrong about it is the whole process. */ private kick; private drain; private post; private resourceAttributes; } /** Build a fetch-based {@link OtelLogExporter}. The workerd-safe opt-in log sink. */ export declare function createOtelLogExporter(config: OtelLogExporterConfig): OtelLogExporter; //# sourceMappingURL=logs.d.ts.map