UNPKG

aethercall

Version:

A scalable WebRTC video calling API built with Node.js and OpenVidu

293 lines (256 loc) 8.87 kB
/** * Abstracted Logging Utility * Provides structured logging with different transports */ const config = require('./config'); class Logger { constructor() { this.logLevel = config.logLevel; this.levels = { error: 0, warn: 1, info: 2, debug: 3 }; this.colors = { error: '\x1b[31m', // Red warn: '\x1b[33m', // Yellow info: '\x1b[36m', // Cyan debug: '\x1b[90m', // Gray reset: '\x1b[0m' }; } /** * Check if message should be logged based on level * @param {string} level - Log level * @returns {boolean} */ shouldLog(level) { return this.levels[level] <= this.levels[this.logLevel]; } /** * Format log message * @param {string} level - Log level * @param {string} message - Log message * @param {Object} meta - Additional metadata * @returns {string} */ formatMessage(level, message, meta = {}) { const timestamp = new Date().toISOString(); const processId = process.pid; let logEntry = { timestamp, level: level.toUpperCase(), pid: processId, message }; // Add metadata if provided if (Object.keys(meta).length > 0) { logEntry.meta = meta; } // In development, use colored console output if (config.isDevelopment()) { const color = this.colors[level] || ''; const reset = this.colors.reset; return `${color}[${timestamp}] ${level.toUpperCase()} (${processId}): ${message}${reset}${ Object.keys(meta).length > 0 ? '\n ' + JSON.stringify(meta, null, 2) : '' }`; } // In production, use JSON format return JSON.stringify(logEntry); } /** * Log error message * @param {string} message - Error message * @param {Object|Error} meta - Error object or metadata */ error(message, meta = {}) { if (!this.shouldLog('error')) return; // Handle Error objects if (meta instanceof Error) { meta = { error: meta.message, stack: meta.stack, name: meta.name }; } const formatted = this.formatMessage('error', message, meta); console.error(formatted); // In production, you might want to send to external logging service if (config.isProduction()) { this.sendToExternalService('error', message, meta); } } /** * Log warning message * @param {string} message - Warning message * @param {Object} meta - Additional metadata */ warn(message, meta = {}) { if (!this.shouldLog('warn')) return; const formatted = this.formatMessage('warn', message, meta); console.warn(formatted); } /** * Log info message * @param {string} message - Info message * @param {Object} meta - Additional metadata */ info(message, meta = {}) { if (!this.shouldLog('info')) return; const formatted = this.formatMessage('info', message, meta); console.log(formatted); } /** * Log debug message * @param {string} message - Debug message * @param {Object} meta - Additional metadata */ debug(message, meta = {}) { if (!this.shouldLog('debug')) return; const formatted = this.formatMessage('debug', message, meta); console.log(formatted); } /** * Log HTTP request * @param {Object} req - Express request object * @param {Object} res - Express response object * @param {number} duration - Request duration in ms */ logRequest(req, res, duration) { const meta = { method: req.method, url: req.originalUrl, status: res.statusCode, duration: `${duration}ms`, userAgent: req.get('User-Agent'), ip: req.ip || req.connection.remoteAddress, requestId: req.context?.requestId }; const level = res.statusCode >= 400 ? 'warn' : 'info'; const message = `${req.method} ${req.originalUrl} ${res.statusCode} - ${duration}ms`; this[level](message, meta); } /** * Log session events * @param {string} event - Event type * @param {string} sessionId - Session ID * @param {Object} data - Event data */ logSession(event, sessionId, data = {}) { this.info(`Session ${event}`, { event, sessionId, ...data }); } /** * Log connection events * @param {string} event - Event type * @param {string} connectionId - Connection ID * @param {Object} data - Event data */ logConnection(event, connectionId, data = {}) { this.info(`Connection ${event}`, { event, connectionId, ...data }); } /** * Log recording events * @param {string} event - Event type * @param {string} recordingId - Recording ID * @param {Object} data - Event data */ logRecording(event, recordingId, data = {}) { this.info(`Recording ${event}`, { event, recordingId, ...data }); } /** * Log authentication events * @param {string} event - Event type * @param {string} clientId - Client ID * @param {Object} data - Event data */ logAuth(event, clientId, data = {}) { this.info(`Auth ${event}`, { event, clientId, ...data }); } /** * Create child logger with context * @param {Object} context - Context to include in all logs * @returns {Object} Child logger */ child(context = {}) { const parent = this; return { error: (message, meta = {}) => parent.error(message, { ...context, ...meta }), warn: (message, meta = {}) => parent.warn(message, { ...context, ...meta }), info: (message, meta = {}) => parent.info(message, { ...context, ...meta }), debug: (message, meta = {}) => parent.debug(message, { ...context, ...meta }), child: (additionalContext) => parent.child({ ...context, ...additionalContext }) }; } /** * Send logs to external service (placeholder) * @param {string} level - Log level * @param {string} message - Log message * @param {Object} meta - Metadata */ sendToExternalService(level, message, meta) { // TODO: Implement external logging service integration // Examples: Winston with transports, Logstash, Datadog, etc. // For now, this is a placeholder // In production, you might want to: // - Send to Elasticsearch/Logstash // - Send to cloud logging services (AWS CloudWatch, Google Cloud Logging, etc.) // - Send to monitoring services (Datadog, New Relic, etc.) // - Store in database for analysis } /** * Performance timer utility * @param {string} label - Timer label * @returns {Function} Function to end timer and log duration */ timer(label) { const start = Date.now(); return (message = '', meta = {}) => { const duration = Date.now() - start; this.debug(`${label} ${message}`, { duration: `${duration}ms`, ...meta }); return duration; }; } /** * Log system metrics */ logMetrics() { const memUsage = process.memoryUsage(); const cpuUsage = process.cpuUsage(); this.debug('System metrics', { memory: { rss: `${Math.round(memUsage.rss / 1024 / 1024)}MB`, heapTotal: `${Math.round(memUsage.heapTotal / 1024 / 1024)}MB`, heapUsed: `${Math.round(memUsage.heapUsed / 1024 / 1024)}MB`, external: `${Math.round(memUsage.external / 1024 / 1024)}MB` }, cpu: { user: cpuUsage.user, system: cpuUsage.system }, uptime: `${Math.round(process.uptime())}s` }); } } // Create and export singleton instance const logger = new Logger(); module.exports = logger;