const fs = require('fs'); const path = require('path'); class ApiDebugLogger { constructor() { this.logFile = path.join(__dirname, '..', '..', 'api_debug.log'); this.enabled = process.env.NODE_ENV === 'development' || process.env.API_DEBUG === 'true'; // Debug logging setup if (this.enabled) { console.log(`🐛 ApiDebugLogger: Enabled (NODE_ENV=${process.env.NODE_ENV}, API_DEBUG=${process.env.API_DEBUG})`); console.log(`🐛 ApiDebugLogger: Log file path: ${this.logFile}`); // Ensure the log file exists try { if (!fs.existsSync(this.logFile)) { fs.writeFileSync(this.logFile, `# API Debug Log Started at ${new Date().toISOString()}\n`); console.log(`🐛 ApiDebugLogger: Created log file at ${this.logFile}`); } } catch (error) { console.error(`❌ ApiDebugLogger: Failed to create log file: ${error}`); } } else { console.log(`🐛 ApiDebugLogger: Disabled (NODE_ENV=${process.env.NODE_ENV}, API_DEBUG=${process.env.API_DEBUG})`); } } log(method, url, statusCode, requestBody = {}, responseBody = {}, headers = {}) { if (!this.enabled) return; const timestamp = new Date().toISOString(); const sanitizedRequest = this.sanitizeData(requestBody); const sanitizedResponse = this.sanitizeData(responseBody); const sanitizedHeaders = this.sanitizeHeaders(headers); const logEntry = [ `[${timestamp}]`, method.toUpperCase(), url, `-`, `STATUS:${statusCode}`, `-`, `REQ:${JSON.stringify(sanitizedRequest)}`, `-`, `RES:${JSON.stringify(sanitizedResponse)}`, `-`, `HEADERS:${JSON.stringify(sanitizedHeaders)}` ].join(' '); try { fs.appendFileSync(this.logFile, logEntry + '\n'); console.log(`🐛 API Log: ${method.toUpperCase()} ${url} - ${statusCode}`); } catch (error) { console.error('❌ Failed to write to API debug log:', error); } } sanitizeData(data) { if (!data || typeof data !== 'object') return data; const sanitized = { ...data }; // Remove sensitive fields const sensitiveFields = ['password', 'token', 'secret', 'key', 'auth', 'authorization']; sensitiveFields.forEach(field => { if (sanitized[field]) { sanitized[field] = '***REDACTED***'; } }); return sanitized; } sanitizeHeaders(headers) { if (!headers || typeof headers !== 'object') return {}; const sanitized = { ...headers }; // Remove sensitive headers const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-auth-token']; sensitiveHeaders.forEach(header => { if (sanitized[header]) { sanitized[header] = '***REDACTED***'; } }); return sanitized; } logRequest(req) { if (!this.enabled) return; const timestamp = new Date().toISOString(); const logEntry = `[${timestamp}] INCOMING ${req.method} ${req.url} - BODY:${JSON.stringify(this.sanitizeData(req.body))} - HEADERS:${JSON.stringify(this.sanitizeHeaders(req.headers))}`; try { fs.appendFileSync(this.logFile, logEntry + '\n'); console.log(`🐛 API Request: ${req.method} ${req.url}`); } catch (error) { console.error('❌ Failed to write request to API debug log:', error); } } logResponse(req, res, responseBody) { if (!this.enabled) return; this.log( req.method, req.url, res.statusCode, req.body, responseBody, { 'content-type': res.getHeader('content-type'), 'user-agent': req.headers['user-agent'] } ); } clear() { try { fs.writeFileSync(this.logFile, '# API Debug Log Cleared at ' + new Date().toISOString() + '\n'); console.log('API debug log cleared'); } catch (error) { console.error('Failed to clear API debug log:', error); } } } // Middleware function for Express function apiDebugMiddleware(req, res, next) { const logger = new ApiDebugLogger(); // Log incoming request logger.logRequest(req); // Override res.json to capture response const originalJson = res.json; res.json = function(data) { logger.logResponse(req, res, data); return originalJson.call(this, data); }; next(); } module.exports = { ApiDebugLogger, apiDebugMiddleware };