Skip to main content
Glama

Google Drive MCP Server

by ducla5
request-logger.ts5.79 kB
/** * Request logging middleware for debugging and monitoring */ import { logger } from './logger.js'; import { randomUUID } from 'crypto'; export interface RequestContext { requestId: string; startTime: number; method: string; path: string; userId: string | undefined; userAgent: string | undefined; ip: string | undefined; } export class RequestLogger { private activeRequests = new Map<string, RequestContext>(); /** * Start request logging */ public startRequest( method: string, path: string, headers?: Record<string, string>, userId?: string ): string { const requestId = randomUUID(); const startTime = Date.now(); const context: RequestContext = { requestId, startTime, method, path, userId, userAgent: headers?.['user-agent'], ip: headers?.['x-forwarded-for'] || headers?.['x-real-ip'] }; this.activeRequests.set(requestId, context); // Log request start logger.logRequest(requestId, method, path, userId); // Log request details in debug mode logger.debug('Request details', { requestId, headers: this.sanitizeHeaders(headers), userAgent: context.userAgent, ip: context.ip }); return requestId; } /** * End request logging */ public endRequest( requestId: string, statusCode: number, responseSize?: number, error?: Error ): void { const context = this.activeRequests.get(requestId); if (!context) { logger.warn('Attempted to end unknown request', { requestId }); return; } const duration = Date.now() - context.startTime; // Log response logger.logResponse(requestId, statusCode, duration, context.userId); // Log additional response details in debug mode logger.debug('Response details', { requestId, statusCode, duration, responseSize, success: statusCode < 400 }); // Log error if present if (error) { logger.error('Request failed with error', error, { requestId, statusCode, duration, method: context.method, path: context.path }); } // Clean up this.activeRequests.delete(requestId); } /** * Log request body (for debugging) */ public logRequestBody(requestId: string, body: any): void { const context = this.activeRequests.get(requestId); if (!context) { return; } logger.debug('Request body', { requestId, bodyType: typeof body, bodySize: JSON.stringify(body).length, body: this.sanitizeBody(body) }); } /** * Log response body (for debugging) */ public logResponseBody(requestId: string, body: any): void { const context = this.activeRequests.get(requestId); if (!context) { return; } logger.debug('Response body', { requestId, bodyType: typeof body, bodySize: JSON.stringify(body).length, body: this.sanitizeBody(body) }); } /** * Log API operation within a request */ public logOperation( requestId: string, operation: string, success: boolean, duration: number, details?: Record<string, any> ): void { const context = this.activeRequests.get(requestId); logger.logOperation(operation, success, duration, { requestId, userId: context?.userId, ...details }); } /** * Get active request count */ public getActiveRequestCount(): number { return this.activeRequests.size; } /** * Get active requests */ public getActiveRequests(): RequestContext[] { return Array.from(this.activeRequests.values()); } /** * Clean up stale requests (older than 5 minutes) */ public cleanupStaleRequests(): void { const fiveMinutesAgo = Date.now() - (5 * 60 * 1000); for (const [requestId, context] of this.activeRequests.entries()) { if (context.startTime < fiveMinutesAgo) { logger.warn('Cleaning up stale request', { requestId, age: Date.now() - context.startTime, method: context.method, path: context.path }); this.activeRequests.delete(requestId); } } } /** * Sanitize headers for logging (remove sensitive data) */ private sanitizeHeaders(headers?: Record<string, string>): Record<string, string> { if (!headers) return {}; const sanitized = { ...headers }; const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-auth-token']; for (const header of sensitiveHeaders) { if (sanitized[header]) { sanitized[header] = '[REDACTED]'; } } return sanitized; } /** * Sanitize body for logging (remove sensitive data and limit size) */ private sanitizeBody(body: any): any { if (!body) return body; try { const bodyStr = JSON.stringify(body); // Limit body size in logs if (bodyStr.length > 1000) { return `[TRUNCATED - ${bodyStr.length} chars] ${bodyStr.substring(0, 1000)}...`; } // Remove sensitive fields if (typeof body === 'object') { const sanitized = { ...body }; const sensitiveFields = ['password', 'token', 'secret', 'key', 'auth']; for (const field of sensitiveFields) { if (sanitized[field]) { sanitized[field] = '[REDACTED]'; } } return sanitized; } return body; } catch (error) { return '[UNPARSEABLE BODY]'; } } } // Export singleton instance export const requestLogger = new RequestLogger(); // Cleanup stale requests every minute setInterval(() => { requestLogger.cleanupStaleRequests(); }, 60000);

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