autosnippet
Version:
Extract code patterns into a knowledge base for AI coding assistants
105 lines (104 loc) • 3.84 kB
JavaScript
import Logger from '../../infrastructure/logging/Logger.js';
/** AuditLogger - 审计日志记录器 */
export class AuditLogger {
auditStore;
logger;
#eventBus;
constructor(auditStore, eventBus) {
this.auditStore = auditStore;
this.logger = Logger.getInstance();
this.#eventBus = eventBus ?? null;
}
/**
* 记录审计日志
* 兼容两种传入格式:
* Gateway 风格: { actor, action, resource, result, data, duration }
* Service 风格: { actor, action, resourceType, resourceId, details, timestamp }
*/
async log(entry) {
// 兼容 Service 层传入 resourceType + resourceId(而非 resource)
const resource = entry.resource ||
(entry.resourceType && entry.resourceId
? `${entry.resourceType}:${entry.resourceId}`
: undefined);
// 兼容 Service 层传入 details(而非 data)
const data = entry.data || (entry.details ? { details: entry.details } : {});
const auditEntry = {
id: entry.requestId || this.generateId(),
timestamp: Date.now(),
actor: entry.actor,
actor_context: JSON.stringify(entry.context || {}),
action: entry.action,
resource: this.formatResource(resource),
operation_data: JSON.stringify(data),
result: entry.result || 'success',
error_message: entry.error || null,
duration: entry.duration || null,
};
try {
await this.auditStore.save(auditEntry);
this.logger.debug('Audit log recorded', {
requestId: entry.requestId,
actor: entry.actor,
action: entry.action,
});
// 实时推送审计事件到 Dashboard(M7 §6 audit:entry Socket.io)
if (this.#eventBus) {
this.#eventBus.emit('audit:entry', {
id: auditEntry.id,
timestamp: auditEntry.timestamp,
actor: auditEntry.actor,
action: auditEntry.action,
resource: auditEntry.resource,
result: auditEntry.result,
});
}
}
catch (error) {
// 审计失败不应阻断业务,仅记录错误
this.logger.error('Failed to save audit log', {
error: error.message,
entry: auditEntry,
});
}
}
/** 生成 ID */
generateId() {
return `audit_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/** 格式化资源 */
formatResource(resource) {
if (typeof resource === 'string') {
return resource;
}
if (typeof resource === 'object' && resource !== null) {
return JSON.stringify(resource);
}
return String(resource);
}
/** 查询审计日志 */
async query(filters) {
return await this.auditStore.query(filters);
}
/** 获取特定请求的日志 */
async getByRequestId(requestId) {
return await this.auditStore.findByRequestId(requestId);
}
/** 获取特定角色的日志 */
async getByActor(actor, limit = 100) {
return await this.auditStore.findByActor(actor, limit);
}
/** 获取特定操作的日志 */
async getByAction(action, limit = 100) {
return await this.auditStore.findByAction(action, limit);
}
/** 获取失败的操作日志 */
async getFailures(limit = 100) {
return await this.auditStore.findByResult('failure', limit);
}
/** 统计审计数据 */
async getStats(timeRange) {
return await this.auditStore.getStats(timeRange);
}
}
export default AuditLogger;