feat(audit): Add automation component logging
Add audit logging to: - WebhookHandler: connect/disconnect, receive, not_found, denied, HMAC verified - HeartbeatMonitor: start/stop, cycle, check, fail, recover - GmailWatcher: connect/disconnect lifecycle events All automation events now captured in audit log with proper context
This commit is contained in:
@@ -2,6 +2,7 @@ import { statfsSync, accessSync, constants as fsConstants } from 'fs';
|
||||
import { request } from 'http';
|
||||
import type { HeartbeatConfig, HeartbeatCheck } from '../config/schema.js';
|
||||
import type { ChannelAdapter, ChannelStatus, OutboundMessage } from '../channels/types.js';
|
||||
import { auditLogger } from '../audit/index.js';
|
||||
|
||||
/** Result of a single health check. */
|
||||
export interface CheckResult {
|
||||
@@ -77,6 +78,7 @@ export class HeartbeatMonitor {
|
||||
|
||||
const intervalMs = parseInterval(this.deps.config.interval);
|
||||
console.log(`HeartbeatMonitor: starting (interval=${this.deps.config.interval}, checks=[${this.deps.config.checks.join(', ')}])`);
|
||||
auditLogger?.systemStart('HeartbeatMonitor', { interval: this.deps.config.interval, checks: this.deps.config.checks });
|
||||
|
||||
this.timer = setInterval(() => {
|
||||
this.runChecks().catch((err) => {
|
||||
@@ -96,6 +98,7 @@ export class HeartbeatMonitor {
|
||||
clearInterval(this.timer);
|
||||
this.timer = undefined;
|
||||
}
|
||||
auditLogger?.systemStop('HeartbeatMonitor');
|
||||
}
|
||||
|
||||
/** Run all configured checks and return the result. */
|
||||
@@ -136,6 +139,12 @@ export class HeartbeatMonitor {
|
||||
}
|
||||
|
||||
checks.push(result);
|
||||
auditLogger?.heartbeatCheck({
|
||||
check_name: result.name,
|
||||
healthy: result.healthy,
|
||||
message: result.message,
|
||||
duration_ms: result.durationMs,
|
||||
});
|
||||
}
|
||||
|
||||
const healthy = checks.every((c) => c.healthy);
|
||||
@@ -154,16 +163,33 @@ export class HeartbeatMonitor {
|
||||
this.notifiedFailure = true;
|
||||
const failedChecks = checks.filter((c) => !c.healthy).map((c) => `${c.name}: ${c.message}`);
|
||||
await this.notify(`Heartbeat FAILING (${this.consecutiveFailures} consecutive failures):\n${failedChecks.join('\n')}`);
|
||||
|
||||
auditLogger?.heartbeatFail({
|
||||
checks_failed: failedChecks,
|
||||
consecutive_failures: this.consecutiveFailures,
|
||||
threshold: this.deps.config.failure_threshold,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (this.notifiedFailure) {
|
||||
// Recovery notification
|
||||
await this.notify(`Heartbeat RECOVERED after ${this.consecutiveFailures} consecutive failure(s). All checks passing.`);
|
||||
|
||||
auditLogger?.heartbeatRecover({
|
||||
consecutive_failures_before: this.consecutiveFailures,
|
||||
});
|
||||
}
|
||||
this.consecutiveFailures = 0;
|
||||
this.notifiedFailure = false;
|
||||
}
|
||||
|
||||
auditLogger?.heartbeatCycle({
|
||||
interval_ms: parseInterval(this.deps.config.interval),
|
||||
checks: this.deps.config.checks,
|
||||
healthy,
|
||||
consecutive_failures: this.consecutiveFailures,
|
||||
});
|
||||
|
||||
return heartbeatResult;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user