import pino from 'pino' import { join } from 'node:path' import { mkdirSync, existsSync } from 'node:fs' let rootLogger: pino.Logger export interface LoggerConfig { debug: boolean logDir?: string } /** Pretty-print config for console output */ const PRETTY_CONFIG = { colorize: true, translateTime: 'SYS:HH:MM:ss.l', ignore: 'pid,hostname', } as const export function initLogger(config: LoggerConfig): pino.Logger { const { debug, logDir } = config if (debug) { const dir = logDir || join(process.cwd(), '.acp-proxy') if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }) } const now = new Date() const timestamp = now .toISOString() .replace(/T/, '_') .replace(/:/g, '-') .replace(/\..+/, '') const logFile = join(dir, `acp-proxy-${timestamp}.log`) // Debug mode: JSON to file + pretty to console (multistream) rootLogger = pino( { level: 'trace', timestamp: pino.stdTimeFunctions.isoTime, }, pino.transport({ targets: [ { target: 'pino/file', options: { destination: logFile } }, { target: 'pino-pretty', options: { ...PRETTY_CONFIG, destination: 1 }, }, ], }), ) console.log(`📝 Debug logging enabled: ${logFile}`) } else { rootLogger = pino( { level: 'info', timestamp: pino.stdTimeFunctions.isoTime }, pino.transport({ target: 'pino-pretty', options: { ...PRETTY_CONFIG, destination: 1 }, }), ) } return rootLogger } /** Get the root logger (auto-creates a default one if not initialized). */ export function getLogger(): pino.Logger { if (!rootLogger) { rootLogger = pino( { level: 'info' }, pino.transport({ target: 'pino-pretty', options: { ...PRETTY_CONFIG, destination: 1 }, }), ) } return rootLogger } /** * Create a child logger scoped to a module. * Usage: `const log = createLogger("agent"); log.info({ pid }, "spawned")` */ export function createLogger(module: string): pino.Logger { return getLogger().child({ module }) }