api-v1/services/auditLogger.js

107 lines
2.6 KiB
JavaScript

// services/auditLogger.js
/**
* Audit Logging Service
*
* Logs all API requests with user context, action, route, status, and timestamp
* Logs both success and failure cases
*/
// In-memory log store (for development/testing)
// In production, you should integrate with a logging service (e.g., Winston, Bunyan, CloudWatch, etc.)
const auditLogs = [];
/**
* Audit Logger Class
*/
class AuditLogger {
constructor(req) {
this.req = req;
this.userId = req.user?.userId || null;
this.clientIp = req.clientIp || 'unknown';
this.userAgent = req.userAgent || 'unknown';
this.requestId = req.requestId;
this.route = req.path;
this.method = req.method;
}
/**
* Log an audit event
*
* @param {Object} params
* @param {string} params.action - Action being performed
* @param {string} params.status - Status ('success', 'failed', 'forbidden', etc.)
* @param {Object} params.meta - Additional metadata
*/
log({ action, status = 'success', meta = {} }) {
const auditEntry = {
timestamp: new Date().toISOString(),
requestId: this.requestId,
userId: this.userId,
action,
route: this.route,
method: this.method,
status,
clientIp: this.clientIp,
userAgent: this.userAgent,
meta,
};
// In production, send to logging service (e.g., CloudWatch, Elasticsearch, etc.)
// For now, log to console and store in memory
console.log('[AUDIT]', JSON.stringify(auditEntry));
auditLogs.push(auditEntry);
// Keep only last 1000 logs in memory
if (auditLogs.length > 1000) {
auditLogs.shift();
}
// TODO: Integrate with external logging service
// Example:
// if (process.env.LOGGING_SERVICE_URL) {
// axios.post(process.env.LOGGING_SERVICE_URL + '/audit', auditEntry).catch(err => {
// console.error('Failed to send audit log:', err);
// });
// }
}
/**
* Log successful request
*/
logSuccess(action, meta = {}) {
this.log({ action, status: 'success', meta });
}
/**
* Log failed request
*/
logFailure(action, reason, meta = {}) {
this.log({ action, status: 'failed', meta: { ...meta, reason } });
}
/**
* Log forbidden access
*/
logForbidden(action, reason, meta = {}) {
this.log({ action, status: 'forbidden', meta: { ...meta, reason } });
}
}
/**
* Middleware to attach audit logger to request
*/
export function auditLoggerMiddleware(req, res, next) {
req.auditLogger = new AuditLogger(req);
next();
}
/**
* Get audit logs (for debugging/admin purposes)
*/
export function getAuditLogs(limit = 100) {
return auditLogs.slice(-limit);
}
export default AuditLogger;