/** * OTLP/HTTP log exporter — ships structured log records to an OpenTelemetry * collector (or any OTLP/HTTP logs endpoint) as a second, opt-in sink * alongside the always-on local SQLite store. * * Why hand-rolled rather than @opentelemetry/sdk-logs: as of 2026 the OTel JS * Logs SDK is still "Development" (Traces/Metrics are Stable). We emit the * stable OTLP/HTTP JSON wire format (ExportLogsServiceRequest) directly and * reuse the buffer/flush/backoff shape proven by the syslog LogPushWorker. * * Reliability contract (this must NEVER slow down or crash the node): * - push() only appends to a bounded in-memory buffer (drop-oldest on * overflow) and returns immediately; it never awaits the network. * - flush() runs on a timer, is guarded against overlap, and swallows every * error. On a retryable failure the batch is requeued and an exponential * backoff (with jitter, honoring Retry-After) is applied. On a * non-retryable failure the batch is dropped (logged once). * - The flush timer is unref'd so it never keeps the process alive. * - Transport is outbound HTTPS push only — no inbound scrape endpoint. */ import type { LogRecord } from '@origintrail-official/dkg-core'; export type LogLevel = 'debug' | 'info' | 'warn' | 'error'; export interface OtlpLogWorkerOptions { /** Full OTLP/HTTP logs URL, e.g. http://localhost:4318/v1/logs */ endpoint: string; /** Bearer credential for the collector (sent as Authorization: Bearer …). */ token?: string; /** Extra static headers to attach to every request. */ headers?: Record; /** Network identifier: 'testnet' | 'mainnet' | 'devnet'. */ network: string; /** Node's libp2p peer ID. */ peerId: string; nodeName?: string; version?: string; commit?: string; /** 'core' | 'edge' */ role?: string; /** Chain id string, e.g. 'base:8453' → resource attr dkg.chain (matches traces/metrics). */ chainId?: string; /** OTel resource service.name. Default 'dkg-node'. */ serviceName?: string; /** * Per-node identifier. Becomes the OTel `service.instance.id`, which Loki * promotes to the index label `service_instance_id` — this is what a Grafana * "pick a node" dashboard variable selects on. Defaults to nodeName, then * peerId. Hosted nodes should set a unique `name` in config. */ serviceInstanceId?: string; /** * Deployment environment (e.g. 'testnet' | 'mainnet'). Becomes the OTel * `deployment.environment`, which Loki promotes to the label * `deployment_environment`. Defaults to `network`. */ deploymentEnvironment?: string; /** Minimum level forwarded remotely. Default 'info' (debug stays local). */ minLevel?: LogLevel; /** Bounded in-memory buffer; drop-oldest on overflow. Default 500. */ bufferMaxEntries?: number; flushIntervalMs?: number; requestTimeoutMs?: number; /** Initial retry backoff in ms (doubles up to maxBackoffMs). Default 1000. */ baseBackoffMs?: number; /** Ceiling for retry backoff in ms. Default 60000. */ maxBackoffMs?: number; /** Optional diagnostic sink (e.g. the daemon log). Never throws. */ onError?: (message: string) => void; } interface OtlpAttribute { key: string; value: { stringValue: string; }; } export declare class OtlpLogWorker { private buffer; private timer; private stopped; private flushing; private nextAttemptAt; private backoffMs; private droppedNonRetryable; private loggedNonRetryable; private readonly endpoint; private readonly minRank; private readonly maxBuffer; private readonly flushIntervalMs; private readonly requestTimeoutMs; private readonly baseBackoffMs; private readonly maxBackoffMs; private readonly authHeaders; private readonly resourceAttrs; private readonly scopeVersion; private readonly onError; constructor(opts: OtlpLogWorkerOptions); /** Append a record. Filters below minLevel; never awaits the network. */ push(record: LogRecord): void; start(): void; stop(): void; /** * Async teardown for the daemon shutdown / telemetry-disable path: stop the * timer and AWAIT a final flush, so the caller can guarantee no batch is still * being sent (or stranded in the buffer) once this resolves. stop() is the * fire-and-forget variant for callers that can't await. */ shutdown(): Promise; /** Test/diagnostic hook. */ pending(): number; private flush; private requeue; private scheduleBackoff; private post; private buildPayload; } /** * PURE OTLP/HTTP logs wire-format encoder (ExportLogsServiceRequest JSON). * Extracted from `OtlpLogWorker` so the protocol/payload shape is independent * from the worker's scheduling + retry/backoff mechanics (review: "OtlpLogWorker * mixes too many concerns") — change the wire shape here without touching the * buffer/timer logic, and vice-versa. No side effects, no `this`. */ export declare function encodeOtlpLogPayload(batch: ReadonlyArray<{ r: LogRecord; tsMs: number; }>, resourceAttrs: ReadonlyArray, scopeVersion?: string): string; export {}; //# sourceMappingURL=otlp-log-worker.d.ts.map