import pino, { Logger as PinoLogger } from 'pino'; import { LoggerConfig } from '../types'; /** * A highly configurable and structured logging utility using Pino. * This ensures that logs are clean, fast, and easy to parse, * while still being human-readable in the terminal via pino-pretty. */ export class Logger { private static instance: Logger; private logger: PinoLogger; private constructor(config: LoggerConfig = {}) { const { level = 'info', prettyPrint = true } = config; this.logger = pino({ level: level, timestamp: () => `,"time":"${new Date().toISOString()}"`, // Use pino-pretty for development/terminal output transport: prettyPrint ? { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:HH:MM:ss Z', ignore: 'pid,hostname', }, } : undefined, }); this.logger.info({ config: { level, prettyPrint } }, 'Logger initialized successfully.'); } /** * Get the singleton instance of the Logger. * @param config Configuration for the logger (only used on first initialization). * @returns The Logger instance. */ public static getInstance(config?: LoggerConfig): Logger { if (!Logger.instance) { Logger.instance = new Logger(config); } return Logger.instance; } /** * Get the underlying Pino logger instance. * @returns The PinoLogger instance. */ public getLogger(): PinoLogger { return this.logger; } /** * Log a debug message. * @param msg The message to log. * @param obj Optional object to include in the log. */ public debug(msg: string, obj?: object): void { this.logger.debug(obj, msg); } /** * Log an info message. * @param msg The message to log. * @param obj Optional object to include in the log. */ public info(msg: string, obj?: object): void { this.logger.info(obj, msg); } /** * Log a warning message. * @param msg The message to log. * @param obj Optional object to include in the log. */ public warn(msg: string, obj?: object): void { this.logger.warn(obj, msg); } /** * Log an error message. * @param msg The message to log. * @param obj Optional object to include in the log. */ public error(msg: string, obj?: object): void { this.logger.error(obj, msg); } /** * Log a fatal error message. * @param msg The message to log. * @param obj Optional object to include in the log. */ public fatal(msg: string, obj?: object): void { this.logger.fatal(obj, msg); } }