150 lines
4.5 KiB
JavaScript
150 lines
4.5 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
class ApiDebugLogger {
|
|
constructor() {
|
|
// Use mounted volume directory that's accessible from host
|
|
this.logFile = '/app/debug_logs/api_debug.log';
|
|
this.enabled = process.env.NODE_ENV === 'development' || process.env.API_DEBUG === 'true';
|
|
this.fileLoggingEnabled = false;
|
|
|
|
// 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 debug_logs directory exists
|
|
try {
|
|
const fs = require('fs');
|
|
const debugDir = '/app/debug_logs';
|
|
if (!fs.existsSync(debugDir)) {
|
|
fs.mkdirSync(debugDir, { recursive: true });
|
|
console.log(`🐛 ApiDebugLogger: Created debug logs directory at ${debugDir}`);
|
|
}
|
|
|
|
fs.writeFileSync(this.logFile, `# API Debug Log Started at ${new Date().toISOString()}\n`);
|
|
this.fileLoggingEnabled = true;
|
|
console.log(`🐛 ApiDebugLogger: File logging enabled at ${this.logFile} (mounted to host: ./debug_logs/)`);
|
|
} catch (error) {
|
|
console.warn(`⚠️ ApiDebugLogger: File logging disabled - using console only. Error: ${error.message}`);
|
|
this.fileLoggingEnabled = false;
|
|
}
|
|
} 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(' ');
|
|
|
|
// Always log to console
|
|
console.log(`🐛 API Log: ${method.toUpperCase()} ${url} - ${statusCode}`);
|
|
|
|
// Try to log to file if enabled
|
|
if (this.fileLoggingEnabled) {
|
|
try {
|
|
fs.appendFileSync(this.logFile, logEntry + '\n');
|
|
} catch (error) {
|
|
console.warn(`⚠️ File logging failed, disabling: ${error.message}`);
|
|
this.fileLoggingEnabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
sanitizeData(data) {
|
|
// For debugging, return data as-is without redaction
|
|
return data;
|
|
}
|
|
|
|
sanitizeHeaders(headers) {
|
|
// For debugging, return headers as-is without redaction
|
|
return headers;
|
|
}
|
|
|
|
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))}`;
|
|
|
|
// Always log to console
|
|
console.log(`🐛 API Request: ${req.method} ${req.url}`);
|
|
|
|
// Try to log to file if enabled
|
|
if (this.fileLoggingEnabled) {
|
|
try {
|
|
fs.appendFileSync(this.logFile, logEntry + '\n');
|
|
} catch (error) {
|
|
console.warn(`⚠️ File logging failed, disabling: ${error.message}`);
|
|
this.fileLoggingEnabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
};
|