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
text/typescript
/**
* 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;