// src/services/logger.server.ts /** * SERVER-SIDE LOGGER * This file configures and exports a singleton `pino` logger instance for * server-side use, adhering to ADR-004 for structured JSON logging. */ import pino from 'pino'; const isProduction = process.env.NODE_ENV === 'production'; const isTest = process.env.NODE_ENV === 'test'; export const logger = pino({ level: isProduction ? 'info' : 'debug', // Use pino-pretty for human-readable logs in development, and JSON in production. // Disable transport in tests to prevent worker thread issues. transport: isProduction || isTest ? undefined : { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:standard', ignore: 'pid,hostname', // These are useful in production, but noisy in dev. }, }, // As per ADR-004, we centralize sanitization here. // This automatically redacts sensitive fields from all log objects. // The paths target keys within objects passed to the logger. redact: { paths: [ 'req.headers.authorization', 'req.headers.cookie', '*.body.password', '*.body.newPassword', '*.body.currentPassword', '*.body.confirmPassword', '*.body.refreshToken', '*.body.token', ], censor: '[REDACTED]', }, }); const debugModules = (process.env.DEBUG_MODULES || '').split(',').map((s) => s.trim()); export const createScopedLogger = (moduleName: string) => { // If DEBUG_MODULES contains "ai-service" or "*", force level to 'debug' const isDebugEnabled = debugModules.includes('*') || debugModules.includes(moduleName); return logger.child({ module: moduleName, level: isDebugEnabled ? 'debug' : logger.level, }); };