1
0

feat: 动态粒度趋势图,支持 auto bucket 选择 + P95 延迟 + 状态条

This commit is contained in:
2026-05-23 23:53:18 +08:00
parent 6601ab458d
commit 4f33fba793
16 changed files with 315 additions and 106 deletions

View File

@@ -2,11 +2,12 @@ import { describe, expect, test } from "bun:test";
import {
analyzeIncidentSequence,
buildHourlyTrend,
buildTrend,
calculateAvailability,
calculateCurrentStreak,
calculatePercentile,
type MetricCheckpoint,
resolveAutoBucket,
} from "../../src/server/metrics";
describe("后端指标计算", () => {
@@ -90,35 +91,47 @@ describe("后端指标计算", () => {
});
test("UTC 小时趋势分桶返回 up/down 和延迟范围", () => {
const trend = buildHourlyTrend([
const checkpoints = [
checkpoint("2025-01-01T00:10:00.000Z", true, 100),
checkpoint("2025-01-01T00:40:00.000Z", false, null),
checkpoint("2025-01-01T01:05:00.000Z", true, 300),
]);
];
const trend = buildTrend(checkpoints, "2025-01-01T00:00:00.000Z", "2025-01-01T01:59:59.999Z", "1h");
expect(trend).toEqual([
{
availability: 50,
avgDurationMs: 100,
bucketEnd: "2025-01-01T01:00:00.000Z",
bucketStart: "2025-01-01T00:00:00.000Z",
downChecks: 1,
maxDurationMs: 100,
minDurationMs: 100,
p95DurationMs: 100,
totalChecks: 2,
upChecks: 1,
},
{
availability: 100,
avgDurationMs: 300,
bucketEnd: "2025-01-01T01:59:59.999Z",
bucketStart: "2025-01-01T01:00:00.000Z",
downChecks: 0,
maxDurationMs: 300,
minDurationMs: 300,
p95DurationMs: 300,
totalChecks: 1,
upChecks: 1,
},
]);
});
test("resolveAutoBucket 按窗口大小选择合适桶", () => {
expect(resolveAutoBucket(30_000, 7 * 24 * 60 * 60 * 1000)).toBe("1h");
expect(resolveAutoBucket(30_000, 60 * 60 * 1000)).toBe("30s");
expect(resolveAutoBucket(30_000, 24 * 60 * 60 * 1000)).toBe("15m");
});
});
function checkpoint(timestamp: string, matched: boolean, durationMs: null | number = null): MetricCheckpoint {