Skip to main content
Glama

MCP SQL Server

by ryudg
logger.ts6.32 kB
/** * Log level type */ export type LogLevel = 'debug' | 'info' | 'warn' | 'error'; /** * Log metadata interface */ export interface LogMetadata { [key: string]: any; } /** * Log entry interface */ export interface LogEntry { level: LogLevel; message: string; timestamp: string; metadata?: LogMetadata; } /** * Enhanced Logging System * * Features: * - Structured logging * - Multiple log levels * - Metadata support * - Performance optimization */ export class Logger { private logLevel: LogLevel; private enableConsoleOutput: boolean; private logHistory: LogEntry[] = []; private maxHistorySize: number = 1000; constructor(logLevel: LogLevel = 'info', enableConsoleOutput: boolean = true) { this.logLevel = logLevel; this.enableConsoleOutput = enableConsoleOutput; } /** * Map log level priority */ private getLevelPriority(level: LogLevel): number { const priorities = { debug: 0, info: 1, warn: 2, error: 3 }; return priorities[level]; } /** * Check if current log level should be output */ private shouldLog(level: LogLevel): boolean { return this.getLevelPriority(level) >= this.getLevelPriority(this.logLevel); } /** * Format log message */ private formatMessage(level: LogLevel, message: string, metadata?: LogMetadata): string { const timestamp = new Date().toISOString(); const levelStr = level.toUpperCase().padEnd(5); let formattedMessage = `[${timestamp}] [${levelStr}] ${message}`; if (metadata) { try { const metadataStr = JSON.stringify(metadata, null, 2); formattedMessage += ` ${metadataStr}`; } catch (error) { // Handle circular references and other JSON stringify errors formattedMessage += ` [metadata formatting error: ${ error instanceof Error ? error.message : String(error) }]`; } } return formattedMessage; } /** * Save log entry */ private saveLogEntry(level: LogLevel, message: string, metadata?: LogMetadata): void { const entry: LogEntry = { level, message, timestamp: new Date().toISOString(), metadata, }; this.logHistory.push(entry); // Limit history size if (this.logHistory.length > this.maxHistorySize) { this.logHistory = this.logHistory.slice(-this.maxHistorySize); } } /** * Base logging method */ private log(level: LogLevel, message: string, metadata?: LogMetadata): void { if (!this.shouldLog(level)) return; // Save log entry this.saveLogEntry(level, message, metadata); if (this.enableConsoleOutput) { const formattedMessage = this.formatMessage(level, message, metadata); // Console output (use stderr to avoid affecting MCP communication) switch (level) { case 'debug': process.stderr.write(`[DEBUG] ${formattedMessage}\n`); break; case 'info': process.stderr.write(`[INFO] ${formattedMessage}\n`); break; case 'warn': process.stderr.write(`[WARN] ${formattedMessage}\n`); break; case 'error': process.stderr.write(`[ERROR] ${formattedMessage}\n`); break; } } } /** * Debug level logging */ debug(message: string, metadata?: LogMetadata): void { this.log('debug', message, metadata); } /** * Info level logging */ info(message: string, metadata?: LogMetadata): void { this.log('info', message, metadata); } /** * Warning level logging */ warn(message: string, metadata?: LogMetadata): void { this.log('warn', message, metadata); } /** * Error level logging */ error(message: string, metadata?: LogMetadata): void { this.log('error', message, metadata); } /** * Start performance measurement */ startTimer(label: string): () => void { const startTime = process.hrtime.bigint(); return () => { const endTime = process.hrtime.bigint(); const duration = Number(endTime - startTime) / 1_000_000; // Convert to milliseconds this.debug(`Performance measurement: ${label}`, { executionTime: `${duration.toFixed(2)}ms`, label, }); }; } /** * Log query execution */ logQuery(query: string, executionTime: number, success: boolean, metadata?: LogMetadata): void { const queryPreview = query.length > 100 ? `${query.substring(0, 100)}...` : query; if (success) { this.info('Query execution successful', { query: queryPreview, executionTime: `${executionTime}ms`, ...metadata, }); } else { this.error('Query execution failed', { query: queryPreview, executionTime: `${executionTime}ms`, ...metadata, }); } } /** * Log connection status */ logConnection(action: string, success: boolean, metadata?: LogMetadata): void { if (success) { this.info(`Database ${action} successful`, metadata); } else { this.error(`Database ${action} failed`, metadata); } } /** * Log security events */ logSecurityEvent( event: string, severity: 'low' | 'medium' | 'high', metadata?: LogMetadata ): void { const level = severity === 'high' ? 'error' : severity === 'medium' ? 'warn' : 'info'; this.log(level, `Security event: ${event}`, { severity, ...metadata }); } /** * Change log level */ setLogLevel(level: LogLevel): void { this.logLevel = level; this.info(`Log level changed to ${level}.`); } /** * Get log history */ getLogHistory(level?: LogLevel, limit?: number): LogEntry[] { let filtered = this.logHistory; if (level) { filtered = filtered.filter(entry => entry.level === level); } if (limit) { filtered = filtered.slice(-limit); } return filtered; } /** * Clear log history */ clearHistory(): void { this.logHistory = []; // Note: Do not log this action to avoid immediately adding to cleared history } /** * Get log statistics */ getStatistics(): { [level in LogLevel]: number } { const stats = { debug: 0, info: 0, warn: 0, error: 0 }; this.logHistory.forEach(entry => { stats[entry.level]++; }); return stats; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ryudg/mcp-sql'

If you have feedback or need assistance with the MCP directory API, please join our Discord server