import winston from "winston"; import DailyRotateFile from "winston-daily-rotate-file"; import path from "path"; import type { Err } from "@pkg/result"; import util from "util"; process.on("warning", (warning) => { if (warning.message.includes("punycode")) { return; } console.warn(warning); }); const levels = { error: 0, warn: 1, info: 2, http: 3, debug: 4, }; const colors = { error: "red", warn: "yellow", info: "green", http: "magenta", debug: "white", }; const level = () => { const env = process.env.NODE_ENV || "development"; return env === "development" ? "debug" : "warn"; }; const format = 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, ...extra } = info; let formattedMessage = ""; if (message instanceof Error) { formattedMessage = message.stack || message.message; } else if (typeof message === "object") { formattedMessage = util.inspect(message, { depth: null, colors: true }); } else { formattedMessage = message as any as string; } // Handle extra fields (if any) const formattedExtra = Object.keys(extra).length > 0 ? `\n${util.inspect(extra, { depth: null, colors: true })}` : ""; return `[${level}] ${timestamp}: ${formattedMessage}${formattedExtra}`; }), ); const transports = [ new winston.transports.Console(), new DailyRotateFile({ filename: path.join("logs", "error-%DATE%.log"), datePattern: "YYYY-MM-DD", level: "error", maxSize: "5m", maxFiles: "14d", format: format, }), new DailyRotateFile({ filename: path.join("logs", "all-%DATE%.log"), datePattern: "YYYY-MM-DD", maxSize: "5m", maxFiles: "14d", format: format, }), ]; winston.addColors(colors); const Logger = winston.createLogger({ level: level(), levels, format, transports, }); const stream = { write: (message: string) => Logger.http(message.trim()) }; function getError(payload: Err, error?: any) { Logger.error(JSON.stringify({ payload, error }, null, 2)); return { code: payload.code, message: payload.message, userHint: payload.userHint, detail: payload.detail, error: error instanceof Error ? error.message : error, actionable: payload.actionable, } as Err; } export { Logger, stream, getError };