| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { appendFileSync, existsSync, mkdirSync } from "fs"; |
| import { dirname, resolve } from "path"; |
|
|
| const logToFile = process.env.LOG_TO_FILE !== "false"; |
| const logFilePath = resolve(process.env.LOG_FILE_PATH || "logs/application/app.log"); |
|
|
| let initialized = false; |
|
|
| |
| |
| |
| const LEVEL_MAP: Record<string, string> = { |
| debug: "debug", |
| log: "info", |
| info: "info", |
| warn: "warn", |
| error: "error", |
| }; |
|
|
| |
| |
| |
| function ensureDir() { |
| const dir = dirname(logFilePath); |
| if (!existsSync(dir)) { |
| mkdirSync(dir, { recursive: true }); |
| } |
| } |
|
|
| |
| |
| |
| function extractComponent(msg: string): string { |
| const match = msg.match(/^\[([^\]]+)\]/); |
| return match ? match[1] : "app"; |
| } |
|
|
| |
| |
| |
| function argsToMessage(args: unknown[]): string { |
| return args |
| .map((arg) => { |
| if (arg instanceof Error) return `${arg.message}\n${arg.stack || ""}`; |
| if (typeof arg === "object" && arg !== null) { |
| try { |
| return JSON.stringify(arg); |
| } catch { |
| return String(arg); |
| } |
| } |
| return String(arg); |
| }) |
| .join(" "); |
| } |
|
|
| |
| |
| |
| function writeEntry(level: string, args: unknown[]) { |
| try { |
| const message = argsToMessage(args); |
| const entry = { |
| timestamp: new Date().toISOString(), |
| level, |
| component: extractComponent(message), |
| message, |
| }; |
| appendFileSync(logFilePath, JSON.stringify(entry) + "\n"); |
| } catch { |
| |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function initConsoleInterceptor(): void { |
| if (!logToFile || initialized) return; |
|
|
| try { |
| ensureDir(); |
| } catch { |
| |
| return; |
| } |
|
|
| initialized = true; |
|
|
| |
| const originalMethods = { |
| log: console.log.bind(console), |
| info: console.info.bind(console), |
| warn: console.warn.bind(console), |
| error: console.error.bind(console), |
| debug: console.debug.bind(console), |
| }; |
|
|
| |
| for (const [method, level] of Object.entries(LEVEL_MAP)) { |
| const original = originalMethods[method as keyof typeof originalMethods]; |
| if (!original) continue; |
|
|
| (console as unknown as Record<string, unknown>)[method] = (...args: unknown[]) => { |
| |
| original(...args); |
| |
| writeEntry(level, args); |
| }; |
| } |
| } |
|
|