import winston from "winston"; import Transport from "winston-transport"; let cachedLogs = new Map(); export async function initLogHandler() { while (true) { if (cachedLogs.size > 0) { for (let [logType, logs] of cachedLogs) { const url = process.env.LOG_MANAGER_URL!; const defaultLogType = process.env.NODE_APP_NAME!; const body = JSON.stringify({ type: logType === undefined ? defaultLogType : logType, logs: logs, }); try { const response = await fetch(url, { method: "POST", body: body, headers: { "Content-Type": "application/json" }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } cachedLogs.delete(logType); } catch (err) { console.warn(err); } } } await new Promise((resolve) => setTimeout(resolve, Number(process.env.LOG_MANAGER_INTERVAL)) ); } } class MyTransport extends Transport { log(info: any, callback: any) { setImmediate(() => this.emit("logged", info)); const currentDate = new Date(); const formattedDate = `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}:${currentDate.getMilliseconds()}`; let logLevel; switch (info["level"]) { case "info": logLevel = "I"; break; case "debug": logLevel = "D"; break; case "error": logLevel = "E"; break; default: logLevel = "W"; } const msgLocal = `${logLevel} ${formattedDate} ${info["message"]}`; const msg = `${logLevel} ${formattedDate} ${info["logType"]} ${info["message"]}`; if (cachedLogs.has(info["logType"])) { cachedLogs.get(info["logType"]).push(msgLocal); // for testing purposes send all logs to NODE_APP_NAME if (info["logType"] !== process.env.NODE_APP_NAME!) { cachedLogs.get(process.env.NODE_APP_NAME!).push(msg); } } else { cachedLogs.set(info["logType"], [msgLocal]); // for testing purposes send all logs to NODE_APP_NAME if (info["logType"] !== process.env.NODE_APP_NAME!) { cachedLogs.set(process.env.NODE_APP_NAME!, [msg]); } } callback(); } } const winlogger = winston.createLogger({ level: "debug", format: winston.format.json(), transports: [new MyTransport()], }); if (process.env.NODE_ENV !== "production") { winlogger.add( new winston.transports.Console({ format: winston.format.simple(), }) ); } class BaseLogger { constructor(private logTypePrefix: string) {} info(id: string, ...messages: string[]) { this.log("info", id, ...messages); } error(id: string, ...messages: string[]) { this.log("error", id, ...messages); } warn(id: string, ...messages: string[]) { this.log("warn", id, ...messages); } debug(id: string, ...messages: string[]) { this.log("debug", id, ...messages); } private log(level: string, id: string, ...messages: string[]) { winlogger.log({ level: level, logType: `${this.logTypePrefix}-${id}`, message: messages.join(" "), }); } } class UserLogger extends BaseLogger { constructor() { super("user"); } } class StoreLogger extends BaseLogger { constructor() { super("store"); } } class SystemLogger { info(...messages: string[]) { this.log("info", ...messages); } error(...messages: string[]) { this.log("error", ...messages); } warn(...messages: string[]) { this.log("warn", ...messages); } debug(...messages: string[]) { this.log("debug", ...messages); } private log(level: string, ...messages: string[]) { winlogger.log({ level: level, logType: process.env.NODE_APP_NAME, message: messages.join(" "), }); } } export const userLogger = new UserLogger(); export const storeLogger = new StoreLogger(); export const logger = new SystemLogger(); export default logger;