| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 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) {
|
|
|
| try {
|
| process.stderr.write(
|
| `[logger] Failed to set up file transport, attempting sync fallback: ${(err as Error)?.message || err}\n`
|
| );
|
| } catch {}
|
|
|
|
|
|
|
| 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) {
|
| try {
|
| process.stderr.write(
|
| `[logger] Sync fallback also failed, falling back to console only: ${(fallbackErr as Error)?.message || fallbackErr}\n`
|
| );
|
| } catch {}
|
| }
|
| }
|
| }
|
|
|
|
|
| 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;
|
|
|