import { OpenTelemetryTransportV3 } from "@opentelemetry/winston-transport"; import { settings } from "@pkg/settings"; import type { Err } from "@pkg/result"; import winston from "winston"; import util from "util"; process.on("warning", (warning) => { const msg = String(warning?.message || ""); const name = String((warning as any)?.name || ""); if ( name === "TimeoutNegativeWarning" || msg.includes("TimeoutNegativeWarning") || msg.includes("Timeout duration was set to 1") ) { return; } console.warn(warning); }); const levels = { error: 0, warn: 1, info: 2, http: 3, debug: 4, } as const; const colors = { error: "red", warn: "yellow", info: "green", http: "magenta", debug: "white", }; const level = () => { const envLevel = process.env.LOG_LEVEL?.toLowerCase(); if (envLevel && Object.prototype.hasOwnProperty.call(levels, envLevel)) { return envLevel as keyof typeof levels; } return settings.isDevelopment ? "debug" : "warn"; }; const consoleFormat = winston.format.combine( winston.format.errors({ stack: true }), winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }), winston.format.colorize({ all: true }), winston.format.printf((info) => { const { level, message, timestamp } = info; const extra = Object.fromEntries( Object.entries(info).filter( ([key]) => key !== "level" && key !== "message" && key !== "timestamp", ), ); const formattedMessage = message instanceof Error ? message.stack || message.message : typeof message === "object" ? util.inspect(message, { depth: null, colors: true }) : String(message); const formattedExtra = Object.keys(extra).length > 0 ? `\n${util.inspect(extra, { depth: null, colors: true })}` : ""; return `[${level}] ${timestamp}: ${formattedMessage}${formattedExtra}`; }), ); winston.addColors(colors); const logger = winston.createLogger({ level: level(), levels, format: consoleFormat, transports: [ new winston.transports.Console({ format: consoleFormat }), new OpenTelemetryTransportV3(), ], exceptionHandlers: [new winston.transports.Console({ format: consoleFormat })], rejectionHandlers: [new winston.transports.Console({ format: consoleFormat })], }); const stream = { write: (message: string) => logger.http(message.trim()) }; type LogLevel = keyof typeof levels; type ErrorKind = "validation" | "auth" | "db" | "external" | "unknown"; type FlowCtxLike = { flowId: string; userId?: string; sessionId?: string; }; const REDACTED_KEYS = new Set([ "password", "code", "secret", "token", "verificationtoken", "backupcodes", "authorization", "headers", "hash", ]); function sanitizeMeta(input: Record) { const sanitized = Object.fromEntries( Object.entries(input).map(([key, value]) => { if (value === undefined) { return [key, undefined]; } const lowered = key.toLowerCase(); if (REDACTED_KEYS.has(lowered)) { return [key, "[REDACTED]"]; } return [key, value]; }), ); return Object.fromEntries( Object.entries(sanitized).filter(([, value]) => value !== undefined), ); } function classifyError(error: unknown): ErrorKind { if (!error) return "unknown"; if (typeof error === "object" && error && "code" in error) { const code = String((error as { code?: unknown }).code ?? "").toUpperCase(); if (code.includes("AUTH") || code.includes("UNAUTHORIZED")) return "auth"; if (code.includes("VALIDATION") || code.includes("INVALID")) return "validation"; if (code.includes("DB") || code.includes("DATABASE")) return "db"; } return "unknown"; } function errorMessage(error: unknown) { if (error instanceof Error) return error.message; if (typeof error === "string") return error; if (error && typeof error === "object" && "message" in error) { return String((error as { message?: unknown }).message ?? "Unknown error"); } return "Unknown error"; } function writeLog(level: LogLevel, message: string, payload: Record) { switch (level) { case "error": logger.error(message, payload); return; case "warn": logger.warn(message, payload); return; case "debug": logger.debug(message, payload); return; case "http": logger.http(message, payload); return; default: logger.info(message, payload); } } function logDomainEvent({ level = "info", event, fctx, durationMs, error, retryable, meta, }: { level?: LogLevel; event: string; fctx: FlowCtxLike; durationMs?: number; error?: unknown; retryable?: boolean; meta?: Record; }) { const payload: Record = { event, flowId: fctx.flowId, userId: fctx.userId, sessionId: fctx.sessionId, }; if (durationMs !== undefined) payload.duration_ms = durationMs; if (retryable !== undefined) payload.retryable = retryable; if (error !== undefined) { payload.error_kind = classifyError(error); payload.error_message = errorMessage(error); if (error && typeof error === "object" && "code" in error) { payload.error_code = String( (error as { code?: unknown }).code ?? "UNKNOWN", ); } } if (meta) { Object.assign(payload, sanitizeMeta(meta)); } writeLog(level, event, payload); } function getError(payload: Err, error?: any) { logger.error(JSON.stringify({ payload, error }, null, 2)); return { code: payload.code, message: payload.message, description: payload.description, detail: payload.detail, error: error instanceof Error ? error.message : error, actionable: payload.actionable, } as Err; } export { getError, logDomainEvent, logger, stream };