UNPKG

@spaik/mcp-server-roi

Version:

MCP server for AI ROI prediction and tracking with Monte Carlo simulations

191 lines 5.89 kB
import { randomUUID } from 'crypto'; import { logger as baseLogger, createLogger } from './logger.js'; /** * Correlation ID management */ const correlationStore = new Map(); /** * Generate a new correlation ID */ export function generateCorrelationId() { return randomUUID(); } /** * Set correlation ID for a specific context */ export function setCorrelationId(contextKey, correlationId) { correlationStore.set(contextKey, correlationId); } /** * Get correlation ID for a specific context */ export function getCorrelationId(contextKey) { return correlationStore.get(contextKey); } /** * Clear correlation ID for a specific context */ export function clearCorrelationId(contextKey) { correlationStore.delete(contextKey); } /** * Create a logger with correlation ID */ export function createCorrelatedLogger(component, correlationId, additionalContext) { const id = correlationId || generateCorrelationId(); const context = { component, correlationId: id, ...additionalContext }; const baseLoggerInstance = createLogger(context); return { ...baseLoggerInstance, correlationId: id, child: (subComponent, childContext) => { return createCorrelatedLogger(`${component}.${subComponent}`, id, { ...additionalContext, ...childContext }); } }; } /** * Async context manager for correlation IDs */ export class CorrelationContext { static asyncLocalStorage = new Map(); /** * Run an async function with a correlation ID */ static async run(correlationId, fn) { const previousId = this.asyncLocalStorage.get('correlationId'); this.asyncLocalStorage.set('correlationId', correlationId); try { return await fn(); } finally { if (previousId) { this.asyncLocalStorage.set('correlationId', previousId); } else { this.asyncLocalStorage.delete('correlationId'); } } } /** * Get current correlation ID from async context */ static getCurrentId() { return this.asyncLocalStorage.get('correlationId'); } } /** * Express-style middleware for correlation IDs */ export function correlationMiddleware(req, res, next) { const correlationId = req.headers['x-correlation-id'] || generateCorrelationId(); req.correlationId = correlationId; res.setHeader('x-correlation-id', correlationId); CorrelationContext.run(correlationId, async () => { next(); }); } /** * Tool execution logger with correlation */ export function createToolLogger(toolName, correlationId) { return createCorrelatedLogger(`tool.${toolName}`, correlationId || CorrelationContext.getCurrentId(), { toolName, timestamp: new Date().toISOString() }); } /** * API call logger with correlation */ export function createApiLogger(apiName, endpoint, correlationId) { return createCorrelatedLogger(`api.${apiName}`, correlationId || CorrelationContext.getCurrentId(), { apiName, endpoint, timestamp: new Date().toISOString() }); } /** * Database operation logger with correlation */ export function createDbLogger(operation, table, correlationId) { return createCorrelatedLogger('database', correlationId || CorrelationContext.getCurrentId(), { operation, table, timestamp: new Date().toISOString() }); } /** * Performance tracking with correlation */ export class PerformanceTracker { logger; startTime; checkpoints = []; constructor(operationName, correlationId, context) { this.logger = createCorrelatedLogger(`performance.${operationName}`, correlationId || CorrelationContext.getCurrentId(), context); this.startTime = Date.now(); this.logger.debug(`Operation started: ${operationName}`); } checkpoint(name) { const now = Date.now(); const duration = now - this.startTime; const lastCheckpoint = this.checkpoints[this.checkpoints.length - 1]; const sinceLast = lastCheckpoint ? now - lastCheckpoint.time : duration; this.checkpoints.push({ name, time: now, duration }); this.logger.debug(`Checkpoint: ${name}`, { totalDuration: duration, sinceLast, checkpoint: name }); } end(success = true) { const totalDuration = Date.now() - this.startTime; this.logger.info('Operation completed', { success, totalDuration, checkpoints: this.checkpoints.map(cp => ({ name: cp.name, duration: cp.duration })) }); } error(error) { const totalDuration = Date.now() - this.startTime; this.logger.error('Operation failed', error, { totalDuration, checkpoints: this.checkpoints.map(cp => ({ name: cp.name, duration: cp.duration })) }); } } /** * Structured error logging with correlation */ export function logStructuredError(error, context) { const logger = createCorrelatedLogger(context.component, context.correlationId || CorrelationContext.getCurrentId()); const { operation, ...otherContext } = context; logger.error(`${operation} failed`, error, { errorType: error.constructor.name, errorCode: error.code, ...otherContext, operation }); } // Export enhanced logger instance export const structuredLogger = { ...baseLogger, createCorrelated: createCorrelatedLogger, createTool: createToolLogger, createApi: createApiLogger, createDb: createDbLogger, PerformanceTracker, CorrelationContext, generateCorrelationId, logStructuredError }; //# sourceMappingURL=structured-logger.js.map