Skip to main content
Glama

Google Drive MCP Server

by ducla5
logger.ts9.67 kB
/** * Comprehensive logging system with structured logging */ import { appendFileSync, existsSync, mkdirSync } from 'fs'; import { join } from 'path'; export type LogLevel = 'debug' | 'info' | 'warn' | 'error'; export interface LogEntry { timestamp: string; level: LogLevel; message: string; context?: Record<string, any>; error?: { name: string; message: string; stack: string | undefined; }; requestId?: string; userId?: string; operation?: string; duration?: number; } export interface LoggerConfig { level: LogLevel; enableConsole: boolean; enableFile: boolean; logDirectory: string; maxFileSize: number; maxFiles: number; enableStructured: boolean; } export class Logger { private config: LoggerConfig; private logLevels: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 }; constructor(config: Partial<LoggerConfig> = {}) { this.config = { level: 'info', enableConsole: true, enableFile: true, logDirectory: './logs', maxFileSize: 10 * 1024 * 1024, // 10MB maxFiles: 5, enableStructured: true, ...config }; this.ensureLogDirectory(); } /** * Log debug message */ public debug(message: string, context?: Record<string, any>): void { this.log('debug', message, context); } /** * Log info message */ public info(message: string, context?: Record<string, any>): void { this.log('info', message, context); } /** * Log warning message */ public warn(message: string, context?: Record<string, any>): void { this.log('warn', message, context); } /** * Log error message */ public error(message: string, error?: Error, context?: Record<string, any>): void { const errorContext = error ? { name: error.name, message: error.message, stack: error.stack } : undefined; this.log('error', message, context, errorContext); } /** * Log request start */ public logRequest(requestId: string, method: string, path: string, userId?: string): void { this.log('info', `Request started: ${method} ${path}`, { requestId, userId, operation: 'request_start', method, path }); } /** * Log request completion */ public logResponse( requestId: string, statusCode: number, duration: number, userId?: string ): void { this.log('info', `Request completed: ${statusCode}`, { requestId, userId, operation: 'request_complete', statusCode, duration }); } /** * Log API operation */ public logOperation( operation: string, success: boolean, duration: number, context?: Record<string, any> ): void { const level = success ? 'info' : 'error'; const message = `Operation ${operation}: ${success ? 'SUCCESS' : 'FAILED'}`; this.log(level, message, { ...context, operation, success, duration }); } /** * Log performance metrics */ public logPerformance( operation: string, metrics: { duration: number; memoryUsage?: number; cpuUsage?: number; [key: string]: any; } ): void { this.log('debug', `Performance metrics for ${operation}`, { operation: 'performance', operationName: operation, ...metrics }); } /** * Core logging method */ private log( level: LogLevel, message: string, context?: Record<string, any>, error?: { name: string; message: string; stack: string | undefined } ): void { // Check if log level is enabled if (this.logLevels[level] < this.logLevels[this.config.level]) { return; } const logEntry: LogEntry = { timestamp: new Date().toISOString(), level, message, ...(context && { context }), ...(error && { error }), ...(context?.requestId && { requestId: context.requestId }), ...(context?.userId && { userId: context.userId }), ...(context?.operation && { operation: context.operation }), ...(context?.duration && { duration: context.duration }) }; // Console logging if (this.config.enableConsole) { this.logToConsole(logEntry); } // File logging if (this.config.enableFile) { this.logToFile(logEntry); } } /** * Log to console with colors */ private logToConsole(entry: LogEntry): void { const colors = { debug: '\x1b[36m', // Cyan info: '\x1b[32m', // Green warn: '\x1b[33m', // Yellow error: '\x1b[31m' // Red }; const reset = '\x1b[0m'; if (this.config.enableStructured) { console.log(`${colors[entry.level]}[${entry.timestamp}] ${entry.level.toUpperCase()}${reset}: ${entry.message}`); if (entry.context) { console.log(' Context:', JSON.stringify(entry.context, null, 2)); } if (entry.error) { console.log(' Error:', entry.error); } } else { const contextStr = entry.context ? ` | ${JSON.stringify(entry.context)}` : ''; console.log(`${colors[entry.level]}[${entry.timestamp}] ${entry.level.toUpperCase()}${reset}: ${entry.message}${contextStr}`); } } /** * Log to file */ private logToFile(entry: LogEntry): void { const logFile = join(this.config.logDirectory, `app-${new Date().toISOString().split('T')[0]}.log`); const logLine = JSON.stringify(entry) + '\n'; try { // Check file size and rotate if necessary if (existsSync(logFile)) { const stats = require('fs').statSync(logFile); if (stats.size > this.config.maxFileSize) { this.rotateLogFile(logFile); } } appendFileSync(logFile, logLine); } catch (error) { console.error('Failed to write to log file:', error); } } /** * Rotate log files */ private rotateLogFile(currentFile: string): void { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const rotatedFile = currentFile.replace('.log', `-${timestamp}.log`); try { require('fs').renameSync(currentFile, rotatedFile); // Clean up old log files this.cleanupOldLogs(); } catch (error) { console.error('Failed to rotate log file:', error); } } /** * Clean up old log files */ private cleanupOldLogs(): void { try { const fs = require('fs'); const files = fs.readdirSync(this.config.logDirectory) .filter((file: string) => file.endsWith('.log')) .map((file: string) => ({ name: file, path: join(this.config.logDirectory, file), stats: fs.statSync(join(this.config.logDirectory, file)) })) .sort((a: any, b: any) => b.stats.mtime - a.stats.mtime); // Keep only the most recent files if (files.length > this.config.maxFiles) { const filesToDelete = files.slice(this.config.maxFiles); filesToDelete.forEach((file: any) => { fs.unlinkSync(file.path); }); } } catch (error) { console.error('Failed to cleanup old logs:', error); } } /** * Ensure log directory exists */ private ensureLogDirectory(): void { if (!existsSync(this.config.logDirectory)) { try { mkdirSync(this.config.logDirectory, { recursive: true }); } catch (error) { console.error('Failed to create log directory:', error); this.config.enableFile = false; } } } /** * Update logger configuration */ public updateConfig(config: Partial<LoggerConfig>): void { this.config = { ...this.config, ...config }; this.ensureLogDirectory(); } /** * Get current configuration */ public getConfig(): LoggerConfig { return { ...this.config }; } /** * Create child logger with additional context */ public child(context: Record<string, any>): ChildLogger { return new ChildLogger(this, context); } } /** * Child logger that includes additional context in all log entries */ export class ChildLogger { constructor( private parent: Logger, private context: Record<string, any> ) {} public debug(message: string, additionalContext?: Record<string, any>): void { this.parent.debug(message, { ...this.context, ...additionalContext }); } public info(message: string, additionalContext?: Record<string, any>): void { this.parent.info(message, { ...this.context, ...additionalContext }); } public warn(message: string, additionalContext?: Record<string, any>): void { this.parent.warn(message, { ...this.context, ...additionalContext }); } public error(message: string, error?: Error, additionalContext?: Record<string, any>): void { this.parent.error(message, error, { ...this.context, ...additionalContext }); } public logRequest(requestId: string, method: string, path: string, userId?: string): void { this.parent.logRequest(requestId, method, path, userId); } public logResponse(requestId: string, statusCode: number, duration: number, userId?: string): void { this.parent.logResponse(requestId, statusCode, duration, userId); } public logOperation(operation: string, success: boolean, duration: number, context?: Record<string, any>): void { this.parent.logOperation(operation, success, duration, { ...this.context, ...context }); } public logPerformance(operation: string, metrics: { duration: number; [key: string]: any }): void { this.parent.logPerformance(operation, { ...this.context, ...metrics }); } } // Export singleton instance export const logger = new Logger();

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/ducla5/gdriver-mcp'

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