context-engine-mcp
Version:
Context engine MCP server for comprehensive project analysis and multi-file editing
143 lines • 4.74 kB
JavaScript
import winston from 'winston';
import { configManager } from '../config/index.js';
// Custom log levels
const customLevels = {
levels: {
error: 0,
warn: 1,
info: 2,
debug: 3
},
colors: {
error: 'red',
warn: 'yellow',
info: 'green',
debug: 'blue'
}
};
// Create winston logger instance
const createLogger = () => {
const logLevel = configManager.get('logLevel');
const formats = [
winston.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
winston.format.errors({ stack: true }),
winston.format.json()
];
// Add colorization for console output
const consoleFormats = [
winston.format.colorize({ all: true }),
winston.format.printf(({ timestamp, level, message, stack, ...meta }) => {
let log = `${timestamp} [${level}]: ${message}`;
if (Object.keys(meta).length > 0) {
log += ` ${JSON.stringify(meta)}`;
}
if (stack) {
log += `\n${stack}`;
}
return log;
})
];
return winston.createLogger({
levels: customLevels.levels,
level: logLevel,
format: winston.format.combine(...formats),
defaultMeta: { service: 'context-engine-mcp' },
transports: [
// Console transport with colorization - IMPORTANT: Use stderr for STDIO MCP servers
new winston.transports.Console({
format: winston.format.combine(...consoleFormats),
handleExceptions: true,
handleRejections: true,
stderrLevels: ['error', 'warn', 'info', 'debug'] // Force all logs to stderr, not stdout
}),
// File transport for errors
new winston.transports.File({
filename: 'context-engine-error.log',
level: 'error',
maxsize: 5242880, // 5MB
maxFiles: 5,
tailable: true
}),
// File transport for all logs
new winston.transports.File({
filename: 'context-engine-combined.log',
maxsize: 5242880, // 5MB
maxFiles: 3,
tailable: true
})
],
exitOnError: false
});
};
winston.addColors(customLevels.colors);
const logger = createLogger();
// Performance logging helper
export class PerformanceLogger {
startTime;
operation;
constructor(operation) {
this.operation = operation;
this.startTime = performance.now();
logger.debug(`Started operation: ${operation}`);
}
end(additionalInfo) {
const duration = performance.now() - this.startTime;
logger.info(`Completed operation: ${this.operation}`, {
duration: `${duration.toFixed(2)}ms`,
...additionalInfo
});
return duration;
}
checkpoint(checkpoint) {
const duration = performance.now() - this.startTime;
logger.debug(`Checkpoint ${checkpoint} in ${this.operation}`, {
duration: `${duration.toFixed(2)}ms`
});
return duration;
}
}
// Memory usage logging helper
export function logMemoryUsage(operation) {
if (typeof process !== 'undefined' && process.memoryUsage) {
const memUsage = process.memoryUsage();
logger.debug(`Memory usage after ${operation}`, {
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`
});
}
}
// Error logging with context
export function logError(error, context) {
logger.error(error.message, {
name: error.name,
stack: error.stack,
...context
});
}
// Safe logging that won't throw
export function safeLog(level, message, meta) {
try {
logger[level](message, meta);
}
catch (loggingError) {
// Fallback to console if logger fails
console.error('Logging failed:', loggingError);
console[level === 'debug' ? 'log' : level](message, meta);
}
}
// Create child logger with additional context
export function createChildLogger(context) {
return logger.child(context);
}
// Update logger configuration dynamically
export function updateLoggerConfig() {
const newLogLevel = configManager.get('logLevel');
logger.level = newLogLevel;
logger.info('Logger configuration updated', { newLogLevel });
}
export default logger;
//# sourceMappingURL=logger.js.map