// Structured logging utilities for MCP Sigmund
import {
StructuredLogData,
Metadata,
ErrorDetails,
} from './types.js';
import { APP_CONFIG } from './auth.js';
// Log levels
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
}
// Logger class for structured logging
export class Logger {
private serviceName: string;
private version: string;
private environment: string;
private logLevel: LogLevel;
constructor(serviceName: string = 'mcp-sigmund', version: string = '1.0.0') {
this.serviceName = serviceName;
this.version = version;
this.environment = APP_CONFIG?.environment || 'test';
this.logLevel = this.parseLogLevel(APP_CONFIG?.logLevel || 'info');
}
private parseLogLevel(level: string): LogLevel {
switch (level.toLowerCase()) {
case 'debug':
return LogLevel.DEBUG;
case 'info':
return LogLevel.INFO;
case 'warn':
return LogLevel.WARN;
case 'error':
return LogLevel.ERROR;
default:
return LogLevel.INFO;
}
}
private shouldLog(level: LogLevel): boolean {
return level >= this.logLevel;
}
private createStructuredLog(
level: string,
message: string,
context?: string,
metadata?: Metadata,
error?: ErrorDetails
): StructuredLogData {
return {
service: this.serviceName,
version: this.version,
environment: this.environment,
timestamp: new Date().toISOString(),
level,
message,
context,
metadata,
error,
};
}
private log(
level: string,
message: string,
context?: string,
metadata?: Metadata,
error?: ErrorDetails
): void {
if (!APP_CONFIG?.enableStructuredLogging) {
// Fallback to simple console logging
const timestamp = new Date().toISOString();
const contextStr = context ? `[${context}] ` : '';
console.error(
`${timestamp} ${level.toUpperCase()} ${contextStr}${message}`
);
if (error) {
console.error('Error details:', error);
}
if (metadata) {
console.error('Metadata:', metadata);
}
return;
}
const logData = this.createStructuredLog(
level,
message,
context,
metadata,
error
);
console.error(JSON.stringify(logData));
}
debug(message: string, context?: string, metadata?: Metadata): void {
if (this.shouldLog(LogLevel.DEBUG)) {
this.log('debug', message, context, metadata);
}
}
info(message: string, context?: string, metadata?: Metadata): void {
if (this.shouldLog(LogLevel.INFO)) {
this.log('info', message, context, metadata);
}
}
warn(message: string, context?: string, metadata?: Metadata): void {
if (this.shouldLog(LogLevel.WARN)) {
this.log('warn', message, context, metadata);
}
}
error(
message: string,
context?: string,
metadata?: Metadata,
error?: ErrorDetails
): void {
if (this.shouldLog(LogLevel.ERROR)) {
this.log('error', message, context, metadata, error);
}
}
// Specialized logging methods
logDatabaseOperation(
operation: string,
query: string,
executionTime: number,
rowCount: number
): void {
this.debug('Database operation completed', 'database', {
operation,
query: query.substring(0, 100),
execution_time_ms: executionTime,
row_count: rowCount,
});
}
logSlowQuery(query: string, executionTime: number): void {
this.warn('Slow query detected', 'performance', {
query: query.substring(0, 200),
execution_time_ms: executionTime,
threshold_ms: 1000,
});
}
logHealthCheck(
isHealthy: boolean,
responseTime: number,
details?: Metadata
): void {
const level = isHealthy ? 'info' : 'error';
const message = isHealthy ? 'Health check passed' : 'Health check failed';
this.log(level, message, 'health', {
response_time_ms: responseTime,
...details,
});
}
logSecurityEvent(event: string, details: Metadata): void {
this.warn('Security event detected', 'security', {
event,
...details,
});
}
logPerformanceMetrics(metrics: Metadata): void {
this.info('Performance metrics collected', 'performance', metrics);
}
logSystemEvent(event: string, details?: Metadata): void {
this.info(`System event: ${event}`, 'system', details);
}
logUserAction(action: string, context?: string, details?: Metadata): void {
this.info(`User action: ${action}`, context || 'user', details);
}
logError(error: Error, context?: string, metadata?: Metadata): void {
const errorDetails: ErrorDetails = {
message: error.message,
stack: error.stack,
name: error.name,
timestamp: new Date().toISOString(),
};
this.error('An error occurred', context, metadata, errorDetails);
}
}
// Create default logger instance (lazy initialization)
let _logger: Logger | null = null;
export const logger = {
get instance() {
if (!_logger) {
_logger = new Logger();
}
return _logger;
},
};
// Utility functions for backward compatibility
export function logInfo(
message: string,
context?: string,
metadata?: Metadata
): void {
logger.instance.info(message, context, metadata);
}
export function logWarn(
message: string,
context?: string,
metadata?: Metadata
): void {
logger.instance.warn(message, context, metadata);
}
export function logError(
message: string,
context?: string,
metadata?: Metadata,
error?: ErrorDetails
): void {
logger.instance.error(message, context, metadata, error);
}
export function logDebug(
message: string,
context?: string,
metadata?: Metadata
): void {
logger.instance.debug(message, context, metadata);
}