feat: 运行时日志系统,Pino + pino-pretty + pino-roll,console/file 双输出,敏感信息 redaction
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
import { groupBy, isError, Semaphore } from "es-toolkit";
|
||||
|
||||
import type { Logger } from "../logger";
|
||||
import type { ProbeStore } from "./store";
|
||||
import type { CheckResult, ResolvedTargetBase } from "./types";
|
||||
|
||||
import { createNoopLogger } from "../logger";
|
||||
import { errorFailure } from "./expect/failure";
|
||||
import { checkerRegistry } from "./runner";
|
||||
|
||||
const PRUNE_INTERVAL_MS = 3600000;
|
||||
|
||||
export class ProbeEngine {
|
||||
private lastMatched = new Map<string, boolean>();
|
||||
private logger: Logger;
|
||||
private retentionMs: number;
|
||||
private semaphore: Semaphore;
|
||||
private store: ProbeStore;
|
||||
@@ -16,12 +20,20 @@ export class ProbeEngine {
|
||||
private targets: ResolvedTargetBase[];
|
||||
private timers: Array<ReturnType<typeof setInterval>> = [];
|
||||
|
||||
constructor(store: ProbeStore, targets: ResolvedTargetBase[], maxConcurrentChecks?: number, retentionMs?: number) {
|
||||
constructor(
|
||||
store: ProbeStore,
|
||||
targets: ResolvedTargetBase[],
|
||||
maxConcurrentChecks?: number,
|
||||
retentionMs?: number,
|
||||
logger?: Logger,
|
||||
) {
|
||||
this.store = store;
|
||||
this.targets = targets;
|
||||
this.semaphore = new Semaphore(maxConcurrentChecks ?? 20);
|
||||
this.retentionMs = retentionMs ?? 0;
|
||||
this.logger = logger ?? createNoopLogger();
|
||||
this.refreshCache();
|
||||
this.initStateCache();
|
||||
}
|
||||
|
||||
start(): void {
|
||||
@@ -53,6 +65,49 @@ export class ProbeEngine {
|
||||
this.timers = [];
|
||||
}
|
||||
|
||||
private initStateCache(): void {
|
||||
const latestMap = this.store.getLatestChecksMap();
|
||||
for (const [id, row] of latestMap) {
|
||||
this.lastMatched.set(id, row.matched === 1);
|
||||
}
|
||||
}
|
||||
|
||||
private logCheckDebug(result: CheckResult): void {
|
||||
this.logger.debug({
|
||||
durationMs: result.durationMs,
|
||||
failureMessage: result.failure?.message ?? null,
|
||||
failurePhase: result.failure?.phase ?? null,
|
||||
matched: result.matched,
|
||||
targetId: result.targetId,
|
||||
});
|
||||
}
|
||||
|
||||
private logStateChange(result: CheckResult): void {
|
||||
const previous = this.lastMatched.get(result.targetId);
|
||||
const current = result.matched;
|
||||
|
||||
if (previous === undefined) {
|
||||
if (!current) {
|
||||
this.logger.warn(
|
||||
{ durationMs: result.durationMs, failurePhase: result.failure?.phase, targetId: result.targetId },
|
||||
`目标首次 DOWN: ${result.targetId}`,
|
||||
);
|
||||
}
|
||||
} else if (previous && !current) {
|
||||
this.logger.warn(
|
||||
{ durationMs: result.durationMs, failurePhase: result.failure?.phase, targetId: result.targetId },
|
||||
`目标状态变化 UP → DOWN: ${result.targetId}`,
|
||||
);
|
||||
} else if (!previous && current) {
|
||||
this.logger.info(
|
||||
{ durationMs: result.durationMs, targetId: result.targetId },
|
||||
`目标恢复 DOWN → UP: ${result.targetId}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.lastMatched.set(result.targetId, current);
|
||||
}
|
||||
|
||||
private async probeGroup(targets: ResolvedTargetBase[]): Promise<void> {
|
||||
const results = await Promise.allSettled(
|
||||
targets.map(async (target) => {
|
||||
@@ -68,19 +123,25 @@ export class ProbeEngine {
|
||||
for (const [index, result] of results.entries()) {
|
||||
if (result.status === "fulfilled") {
|
||||
this.writeResult(result.value);
|
||||
this.logStateChange(result.value);
|
||||
this.logCheckDebug(result.value);
|
||||
} else {
|
||||
const target = targets[index];
|
||||
console.warn(`探针执行失败: ${formatReason(result.reason)}`);
|
||||
if (!target) continue;
|
||||
this.writeResult({
|
||||
detail: null,
|
||||
durationMs: null,
|
||||
failure: errorFailure("internal", "engine", formatReason(result.reason)),
|
||||
matched: false,
|
||||
observation: null,
|
||||
targetId: target.id,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
if (target) {
|
||||
this.logger.error(
|
||||
{ reason: formatReason(result.reason), targetId: target.id, targetType: target.type },
|
||||
`探针执行失败: ${formatReason(result.reason)}`,
|
||||
);
|
||||
this.writeResult({
|
||||
detail: null,
|
||||
durationMs: null,
|
||||
failure: errorFailure("internal", "engine", formatReason(result.reason)),
|
||||
matched: false,
|
||||
observation: null,
|
||||
targetId: target.id,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user