/** * Единый серверный logger. * * НОВЫЕ модули сервера должны использовать этот logger вместо console.*, * чтобы уровни и формат логов управлялись централизованно: * * import { logger } from "./utils/logger"; * const log = logger("billing"); * log.info("Payment created", { id: 123 }); * * Уровень логирования — env LOG_LEVEL (debug|info|warn|error), по умолчанию info. * Формат — env LOG_FORMAT=json включает JSON-строки (для сборщиков логов), * иначе вывод в историческом формате сервера: "HH:MM:SS AM [source] message", * совместимом с log() из server/vite.ts. * * Массовая замена console.* по существующему коду сознательно не делается — * logger подключается точечно в новых/горячих местах. */ type LogLevel = "debug" | "info" | "warn" | "error"; const LEVEL_ORDER: Record = { debug: 10, info: 20, warn: 30, error: 40, }; function resolveMinLevel(): number { const raw = (process.env.LOG_LEVEL || "info").toLowerCase(); return LEVEL_ORDER[raw as LogLevel] ?? LEVEL_ORDER.info; } const MIN_LEVEL = resolveMinLevel(); const JSON_FORMAT = process.env.LOG_FORMAT === "json"; // Формат времени как в server/vite.ts log() — чтобы строки не отличались function formattedTime(): string { return new Date().toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", second: "2-digit", hour12: true, }); } function serialize(level: LogLevel, source: string, message: string, meta?: unknown): string { if (JSON_FORMAT) { return JSON.stringify({ time: new Date().toISOString(), level, source, message, ...(meta !== undefined ? { meta } : {}), }); } // Ошибки и объекты разворачиваем в читаемую строку let suffix = ""; if (meta instanceof Error) { suffix = ` ${meta.stack || meta.message}`; } else if (meta !== undefined) { try { suffix = ` ${JSON.stringify(meta)}`; } catch { suffix = ` [unserializable meta]`; } } return `${formattedTime()} [${source}] ${message}${suffix}`; } export interface Logger { debug(message: string, meta?: unknown): void; info(message: string, meta?: unknown): void; warn(message: string, meta?: unknown): void; error(message: string, meta?: unknown): void; } export function logger(source: string): Logger { return { debug(message, meta) { if (MIN_LEVEL <= LEVEL_ORDER.debug) console.debug(serialize("debug", source, message, meta)); }, info(message, meta) { if (MIN_LEVEL <= LEVEL_ORDER.info) console.log(serialize("info", source, message, meta)); }, warn(message, meta) { if (MIN_LEVEL <= LEVEL_ORDER.warn) console.warn(serialize("warn", source, message, meta)); }, error(message, meta) { if (MIN_LEVEL <= LEVEL_ORDER.error) console.error(serialize("error", source, message, meta)); }, }; }