UNPKG

recoder-code

Version:

Complete AI-powered development platform with ML model training, plugin registry, real-time collaboration, monitoring, infrastructure automation, and enterprise deployment capabilities

270 lines (229 loc) 7.21 kB
/** * Logger utility for Collaboration Service * Centralized logging with different levels and formats */ import winston from 'winston'; import path from 'path'; // Define custom log levels const logLevels = { error: 0, warn: 1, info: 2, debug: 3, trace: 4 }; // Define colors for each log level const logColors = { error: 'red', warn: 'yellow', info: 'green', debug: 'blue', trace: 'magenta' }; // Add colors to winston winston.addColors(logColors); // Custom format for console output const consoleFormat = winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.colorize({ all: true }), winston.format.printf(({ timestamp, level, message, ...meta }) => { let log = `${timestamp} [${level}]: ${message}`; // Add metadata if present if (Object.keys(meta).length > 0) { log += ` ${JSON.stringify(meta)}`; } return log; }) ); // Custom format for file output const fileFormat = winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.errors({ stack: true }), winston.format.json() ); // Create logger instance const logger = winston.createLogger({ levels: logLevels, level: process.env.LOG_LEVEL || 'info', defaultMeta: { service: 'collaboration-service', environment: process.env.NODE_ENV || 'development' }, transports: [ // Console transport new winston.transports.Console({ format: consoleFormat, handleExceptions: true, handleRejections: true }), // File transport for all logs new winston.transports.File({ filename: path.join('logs', 'collaboration.log'), format: fileFormat, maxsize: 10 * 1024 * 1024, // 10MB maxFiles: 5, tailable: true }), // File transport for error logs only new winston.transports.File({ filename: path.join('logs', 'error.log'), level: 'error', format: fileFormat, maxsize: 10 * 1024 * 1024, // 10MB maxFiles: 5, tailable: true }) ], exitOnError: false }); // Create logs directory if it doesn't exist import fs from 'fs'; const logsDir = path.join(process.cwd(), 'logs'); if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir, { recursive: true }); } // Enhanced logger interface with additional context methods interface Logger extends winston.Logger { collaboration(message: string, meta?: any): void; operation(message: string, meta?: any): void; session(message: string, meta?: any): void; auth(message: string, meta?: any): void; socket(message: string, meta?: any): void; performance(message: string, meta?: any): void; } // Add custom logging methods for different contexts const enhancedLogger = logger as Logger; enhancedLogger.collaboration = function(message: string, meta: any = {}) { this.info(message, { context: 'collaboration', ...meta }); }; enhancedLogger.operation = function(message: string, meta: any = {}) { this.info(message, { context: 'operation', ...meta }); }; enhancedLogger.session = function(message: string, meta: any = {}) { this.info(message, { context: 'session', ...meta }); }; enhancedLogger.auth = function(message: string, meta: any = {}) { this.info(message, { context: 'auth', ...meta }); }; enhancedLogger.socket = function(message: string, meta: any = {}) { this.debug(message, { context: 'socket', ...meta }); }; enhancedLogger.performance = function(message: string, meta: any = {}) { this.info(message, { context: 'performance', ...meta }); }; // Helper functions for structured logging export const logWithContext = (context: string, level: string, message: string, meta: any = {}) => { enhancedLogger.log(level, message, { context, ...meta }); }; export const logError = (error: Error, context?: string, meta: any = {}) => { enhancedLogger.error(error.message, { context: context || 'error', stack: error.stack, ...meta }); }; export const logPerformance = (operation: string, duration: number, meta: any = {}) => { enhancedLogger.performance(`${operation} completed in ${duration}ms`, { operation, duration, ...meta }); }; export const logUserAction = (userId: string, action: string, meta: any = {}) => { enhancedLogger.info(`User action: ${action}`, { context: 'user-action', userId, action, ...meta }); }; export const logSocketEvent = (event: string, socketId: string, meta: any = {}) => { enhancedLogger.socket(`Socket event: ${event}`, { event, socketId, ...meta }); }; export const logSessionEvent = (sessionId: string, event: string, meta: any = {}) => { enhancedLogger.session(`Session event: ${event}`, { sessionId, event, ...meta }); }; export const logCollaborationEvent = (documentId: string, event: string, meta: any = {}) => { enhancedLogger.collaboration(`Collaboration event: ${event}`, { documentId, event, ...meta }); }; export const logOperationEvent = (operationId: string, event: string, meta: any = {}) => { enhancedLogger.operation(`Operation event: ${event}`, { operationId, event, ...meta }); }; // Performance timing utilities export class PerformanceTimer { private startTime: number; private operation: string; private meta: any; constructor(operation: string, meta: any = {}) { this.operation = operation; this.meta = meta; this.startTime = Date.now(); } end(additionalMeta: any = {}) { const duration = Date.now() - this.startTime; logPerformance(this.operation, duration, { ...this.meta, ...additionalMeta }); return duration; } } export const startTimer = (operation: string, meta: any = {}) => { return new PerformanceTimer(operation, meta); }; // Request logging middleware for Express export const requestLogger = (req: any, res: any, next: any) => { const start = Date.now(); const requestId = req.headers['x-request-id'] || `req_${Date.now()}_${Math.random().toString(36).substring(2)}`; // Add request ID to request object req.requestId = requestId; res.on('finish', () => { const duration = Date.now() - start; enhancedLogger.info('HTTP Request', { context: 'http', requestId, method: req.method, url: req.url, statusCode: res.statusCode, duration, userAgent: req.get('User-Agent'), ip: req.ip || req.connection.remoteAddress }); }); next(); }; // Graceful shutdown logging process.on('SIGINT', () => { enhancedLogger.info('Received SIGINT, shutting down gracefully'); }); process.on('SIGTERM', () => { enhancedLogger.info('Received SIGTERM, shutting down gracefully'); }); process.on('uncaughtException', (error) => { enhancedLogger.error('Uncaught Exception', { context: 'uncaught-exception', error: error.message, stack: error.stack }); }); process.on('unhandledRejection', (reason, promise) => { enhancedLogger.error('Unhandled Rejection', { context: 'unhandled-rejection', reason: reason instanceof Error ? reason.message : String(reason), stack: reason instanceof Error ? reason.stack : undefined }); }); export default enhancedLogger;