import { LEVELS } from './constants'; import { RollupSnapshot } from './analytics/rollups'; import { SseHub } from './analytics/sse-hub'; import type { Server } from 'http'; type LogLevel = keyof typeof LEVELS; type LogMetadata = Record; type HookHandler = (level: LogLevel, message: string, metadata: LogMetadata) => void; type TransportFunction = (info: LogInfo) => void; interface DashboardOptions { /** Mount the dashboard. Express app is taken from the top-level * `expressApp` option (shared with watch middleware). */ enabled?: boolean; /** Master dashboard token. Falls back to `DASHBOARD_TOKEN` env var. */ token?: string; /** Top-left brand text + browser tab title. */ serviceName?: string; /** Logo (same-origin URL, `data:` URI, or inline ``). Drives favicon too. */ logo?: string; /** Logo display size in px (clamped to 12–64). */ logoSize?: number; } interface LoggerOptions { level?: LogLevel; format?: 'json' | 'plain'; console?: boolean; consolePrefix?: string; watch?: boolean; watchPrefix?: string; remote?: boolean; remoteOptions?: Record; /** Dashboard configuration. Replaces the deprecated dashboard-related * keys inside `remoteOptions` (`dashboard`, `dashboardToken`, * `expressApp`, `serviceName`, `logo`, `logoSize`). The old keys still * work but log a one-time deprecation warning. */ dashboardOptions?: DashboardOptions; fileRotate?: boolean; fileFormat?: 'DD-MM-YYYY' | 'DD-MM-YYYY/HH'; fileBackups?: number; fileSize?: number; timezone?: string; use24Hour?: number; dashboard?: boolean; expressApp?: any; sensitiveFields?: string[]; /** Cap on captured response body bytes per HTTP request. Default 64 KB. * Larger responses are tracked (size reported) but the body itself is * replaced with a safe placeholder. */ responseBodyMaxBytes?: number; } interface LogInfo { level: LogLevel; message: string; timestamp: string; [key: string]: any; } declare class Logger { private level; private format; private appPrefix; private console; private consolePrefix; private watch; private watchPrefix; private remote; private remoteOptions; private fileRotate; private fileFormat; private fileBackups; private fileSize; private timezone; private use24Hour; private sensitiveFields; private responseBodyMaxBytes; private colorFormat; private noColorFormat; private transports; private hooks; private watchHandle; private rollups; private sseHub; constructor(options?: LoggerOptions); addTransport(transport: TransportFunction): void; /** * Express middleware that logs request/response details for routes that pass through it. * Requires `watch: true` at construction time. If not enabled, returns a no-op middleware. */ middleware(): (req: any, res: any, next: any) => void; /** * Attach the watcher to a specific http.Server instance. Use this for plain http servers * or non-Express frameworks. Requires `watch: true` at construction time. */ attach(server: Server): void; /** * Register paths whose requests should be silently skipped by the watch * transport. Matches exact paths and any sub-paths (`/api/archive` also * skips `/api/archive/sources`). Used internally by setupDashboard to * keep the dashboard's own polling out of the Requests tab. */ excludeFromWatch(...paths: string[]): void; setLevel(level: LogLevel): void; log(level: LogLevel, message: string, metadata?: LogMetadata): void; private feedAnalytics; private feedAnalyticsFromHttp; /** Snapshot of the current sliding-window rollups (used by /api/analytics). */ getAnalyticsSnapshot(): RollupSnapshot; /** Internal: SSE hub for the dashboard to subscribe to. */ _sseHub(): SseHub; /** Re-ingest a previously-saved log record into the analytics rollups. * Used by setupDashboard's disk-hydration path so the Overview tab * reflects recent activity (events/sec, latency p50/p95/p99, error * sources) immediately after a server restart, instead of starting * at zero until new live traffic arrives. * * IMPORTANT: this calls `this.rollups.ingest` *directly* — it does * NOT go through `feedAnalyticsFromHttp` / `feedAnalytics`. Those * helpers also broadcast via the SSE hub, and the hub's * `onBroadcast` listener (registered in setupDashboard) adds the * payload to `logStorage`. Since `hydrateLogStorageFromDisk` has * already added each disk record to `logStorage` directly, going * through the broadcast path would double-add every record → * HTTP methods donut, status codes, request totals all rendered * at 2× the real count. * * The rollups self-evict past their windows (60s throughput, * 5min latency/errors), so records older than the relevant window * naturally drop off — no filter needed on the caller side. */ _ingestReplay(record: { level?: string; timestamp?: string | number; metadata?: any; message?: string; }): void; private formatTimestamp; debug(message: string, metadata?: LogMetadata): void; info(message: string, metadata?: LogMetadata): void; warn(message: string, metadata?: LogMetadata): void; error(message: string, metadata?: LogMetadata): void; fatal(message: string, metadata?: LogMetadata): void; success(message: string, metadata?: LogMetadata): void; http(message: string, metadata?: LogMetadata): void; custom(message: string, metadata?: LogMetadata): void; hook(event: LogLevel | '*', handler: HookHandler): void; private triggerHooks; } export default Logger;