| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import pino from "pino"; |
| import { resolve } from "path"; |
| import { getLogConfig, initLogRotation } from "@/lib/logRotation"; |
| import { getAppLogLevel } from "@/lib/logEnv"; |
|
|
| const isDev = process.env.NODE_ENV !== "production"; |
|
|
| const baseConfig: pino.LoggerOptions = { |
| level: getAppLogLevel(isDev ? "debug" : "info"), |
| base: { service: "omniroute" }, |
| timestamp: pino.stdTimeFunctions.isoTime, |
| formatters: { |
| level(label: string) { |
| return { level: label }; |
| }, |
| }, |
| }; |
|
|
| function getTransportCompatibleConfig(): pino.LoggerOptions { |
| const { formatters, ...rest } = baseConfig; |
| if (!formatters) return rest; |
|
|
| const { level: _levelFormatter, ...safeFormatters } = formatters; |
| return Object.keys(safeFormatters).length > 0 ? { ...rest, formatters: safeFormatters } : rest; |
| } |
|
|
| |
| |
| |
| |
| function buildLogger(): pino.Logger { |
| const logConfig = getLogConfig(); |
| const logLevel = (baseConfig.level as string) || "info"; |
| const transportConfig = getTransportCompatibleConfig(); |
|
|
| |
| if (logConfig.logToFile) { |
| try { |
| |
| initLogRotation(); |
|
|
| |
| const absLogPath = resolve(logConfig.logFilePath); |
|
|
| if (isDev) { |
| |
| return pino({ |
| ...transportConfig, |
| transport: { |
| targets: [ |
| { |
| target: "pino-pretty", |
| options: { |
| colorize: true, |
| translateTime: "HH:MM:ss.l", |
| ignore: "pid,hostname,service", |
| messageFormat: "[{module}] {msg}", |
| destination: 1, |
| }, |
| level: logLevel, |
| }, |
| { |
| target: "pino/file", |
| options: { destination: absLogPath, mkdir: true }, |
| level: logLevel, |
| }, |
| ], |
| }, |
| }); |
| } |
|
|
| |
| return pino({ |
| ...transportConfig, |
| transport: { |
| targets: [ |
| { |
| target: "pino/file", |
| options: { destination: 1 }, |
| level: logLevel, |
| }, |
| { |
| target: "pino/file", |
| options: { destination: absLogPath, mkdir: true }, |
| level: logLevel, |
| }, |
| ], |
| }, |
| }); |
| } catch (err) { |
| |
| console.warn( |
| "[logger] Failed to set up file transport, attempting sync fallback...", |
| (err as Error)?.message || err |
| ); |
|
|
| |
| |
| try { |
| const absLogPath = resolve(logConfig.logFilePath); |
| const fileDestination = pino.destination({ dest: absLogPath, mkdir: true, sync: true }); |
|
|
| |
| return pino( |
| baseConfig, |
| pino.multistream([ |
| { stream: process.stdout, level: logLevel as pino.Level }, |
| { stream: fileDestination, level: logLevel as pino.Level }, |
| ]) |
| ); |
| } catch (fallbackErr) { |
| console.warn( |
| "[logger] Sync fallback also failed, falling back to console only", |
| (fallbackErr as Error)?.message || fallbackErr |
| ); |
| } |
| } |
| } |
|
|
| |
| if (isDev) { |
| return pino({ |
| ...baseConfig, |
| transport: { |
| target: "pino-pretty", |
| options: { |
| colorize: true, |
| translateTime: "HH:MM:ss.l", |
| ignore: "pid,hostname,service", |
| messageFormat: "[{module}] {msg}", |
| }, |
| }, |
| }); |
| } |
|
|
| return pino(baseConfig); |
| } |
|
|
| export const logger = buildLogger(); |
|
|
| |
| |
| |
| |
| |
| export function createLogger(module: string) { |
| return logger.child({ module }); |
| } |
|
|
| export default logger; |
|
|