const winston = require('winston'); const path = require('path'); const fs = require('fs'); // Create logs directory if it doesn't exist const logsDir = path.join(__dirname, '..', 'logs'); if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir, { recursive: true }); } // Define log format const logFormat = winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.errors({ stack: true }), winston.format.json(), winston.format.printf(({ timestamp, level, message, stack, ...meta }) => { let log = `${timestamp} [${level.toUpperCase()}]: ${message}`; if (stack) { log += `\n${stack}`; } if (Object.keys(meta).length > 0) { log += `\n${JSON.stringify(meta, null, 2)}`; } return log; }) ); // Create logger instance const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: logFormat, defaultMeta: { service: 'ai-agent-backend' }, transports: [ // Console transport new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), winston.format.simple() ) }), // File transport for all logs new winston.transports.File({ filename: path.join(logsDir, 'app.log'), maxsize: 5242880, // 5MB maxFiles: 5, tailable: true }), // File transport for error logs new winston.transports.File({ filename: path.join(logsDir, 'error.log'), level: 'error', maxsize: 5242880, // 5MB maxFiles: 5, tailable: true }) ], // Handle exceptions exceptionHandlers: [ new winston.transports.File({ filename: path.join(logsDir, 'exceptions.log') }) ], // Handle rejections rejectionHandlers: [ new winston.transports.File({ filename: path.join(logsDir, 'rejections.log') }) ] }); // Add request logging middleware logger.logRequest = (req, res, next) => { const start = Date.now(); res.on('finish', () => { const duration = Date.now() - start; const logData = { method: req.method, url: req.url, status: res.statusCode, duration: `${duration}ms`, userAgent: req.get('User-Agent'), ip: req.ip || req.connection.remoteAddress }; if (res.statusCode >= 400) { logger.warn('HTTP Request', logData); } else { logger.info('HTTP Request', logData); } }); next(); }; // Add database query logging logger.logQuery = (sql, params, duration) => { logger.debug('Database Query', { sql, params, duration: `${duration}ms` }); }; // Add device data logging logger.logDeviceData = (deviceId, dataType, data) => { logger.info('Device Data Received', { deviceId, dataType, timestamp: new Date().toISOString(), dataSize: JSON.stringify(data).length }); }; // Add alert logging logger.logAlert = (alertType, severity, message, deviceId = null) => { logger.warn('Alert Generated', { alertType, severity, message, deviceId, timestamp: new Date().toISOString() }); }; // Add AI agent logging logger.logAIAction = (action, details, confidence = null) => { logger.info('AI Agent Action', { action, details, confidence, timestamp: new Date().toISOString() }); }; // Add healing action logging logger.logHealingAction = (action, deviceId, result, duration) => { logger.info('Healing Action', { action, deviceId, result, duration: `${duration}ms`, timestamp: new Date().toISOString() }); }; // Add performance logging logger.logPerformance = (operation, duration, metadata = {}) => { logger.info('Performance Metric', { operation, duration: `${duration}ms`, ...metadata, timestamp: new Date().toISOString() }); }; // Add security logging logger.logSecurity = (event, details, severity = 'info') => { const logMethod = severity === 'error' ? 'error' : 'warn'; logger[logMethod]('Security Event', { event, details, timestamp: new Date().toISOString() }); }; // Add notification logging logger.logNotification = (type, recipient, content, status) => { logger.info('Notification Sent', { type, recipient, content: content.substring(0, 100) + (content.length > 100 ? '...' : ''), status, timestamp: new Date().toISOString() }); }; module.exports = logger;