Commit 21636fc1 by CaIon

feat(performance): enhance uptime calculations and chart data handling

parent 26b6b364
......@@ -60,6 +60,32 @@ function getChartThemeTokens(resolvedTheme: string) {
}
}
const UPTIME_AXIS_MAX = 100
const UPTIME_FOCUSED_AXIS_MIN = 95
const UPTIME_MINOR_OUTAGE_AXIS_MIN = 90
function toUptimeChartValue(value: number): number {
if (!Number.isFinite(value)) return 0
return Math.min(UPTIME_AXIS_MAX, Math.max(0, value))
}
function getUptimeAxisMin(values: number[]): number {
const finiteValues = values.filter((value) => Number.isFinite(value))
if (finiteValues.length === 0) return UPTIME_FOCUSED_AXIS_MIN
const minValue = Math.max(0, Math.min(...finiteValues))
if (minValue >= UPTIME_FOCUSED_AXIS_MIN) return UPTIME_FOCUSED_AXIS_MIN
if (minValue >= UPTIME_MINOR_OUTAGE_AXIS_MIN) {
return UPTIME_MINOR_OUTAGE_AXIS_MIN
}
return Math.max(0, Math.floor((minValue - 5) / 10) * 10)
}
function stripUptimePointSuffix(value: string): string {
return value.replace(/__(start|end)$/, '')
}
// ---------------------------------------------------------------------------
// Latency trend chart (24h, multi-group point-line chart)
// ---------------------------------------------------------------------------
......@@ -173,12 +199,20 @@ export function UptimeTrendChart(props: {
const spec = useMemo(() => {
if (props.series.length === 0) return null
const data = props.series.map((point) => ({
const rawData = props.series.map((point) => ({
date: formatDayLabel(point.date),
uptime: point.uptime_pct,
uptime: toUptimeChartValue(point.uptime_pct),
incidents: point.incidents,
outage: point.outage_minutes,
}))
const data =
rawData.length === 1
? [
{ ...rawData[0], date: `${rawData[0].date}__start` },
{ ...rawData[0], date: `${rawData[0].date}__end` },
]
: rawData
const axisMin = getUptimeAxisMin(rawData.map((point) => point.uptime))
return {
type: 'line' as const,
......@@ -204,7 +238,9 @@ export function UptimeTrendChart(props: {
},
tooltip: {
mark: {
title: { value: (d: { date: string }) => d.date },
title: {
value: (d: { date: string }) => stripUptimePointSuffix(d.date),
},
content: [
{
key: t('Uptime'),
......@@ -225,6 +261,8 @@ export function UptimeTrendChart(props: {
{
orient: 'bottom',
label: {
formatMethod: (val: number | string) =>
stripUptimePointSuffix(String(val)),
style: { fill: textColor, fontSize: 10 },
autoLimit: true,
},
......@@ -232,8 +270,8 @@ export function UptimeTrendChart(props: {
},
{
orient: 'left',
min: 95,
max: 100,
min: axisMin,
max: UPTIME_AXIS_MAX,
label: {
formatMethod: (val: number | string) => `${val}%`,
style: { fill: textColor, fontSize: 10 },
......
......@@ -79,6 +79,12 @@ type PerformanceRow = {
avg_tps: number
}
function toUptimePct(value: number): number {
if (!Number.isFinite(value)) return 0
const clamped = Math.min(100, Math.max(0, value))
return Math.round(clamped * 100) / 100
}
function toLatencySeries(groups: PerformanceGroup[]) {
const byTs = new Map<number, number[]>()
for (const group of groups) {
......@@ -107,8 +113,9 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] {
for (const point of group.series) {
const current = byTs.get(point.ts) ?? { rates: [], incidents: 0 }
if (Number.isFinite(point.success_rate)) {
current.rates.push(point.success_rate)
if (point.success_rate < 100) current.incidents += 1
const successRate = toUptimePct(point.success_rate)
current.rates.push(successRate)
if (successRate < 100) current.incidents += 1
}
byTs.set(point.ts, current)
}
......@@ -123,7 +130,7 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] {
: 0
return {
date: new Date(ts * 1000).toISOString(),
uptime_pct: Math.round(uptime * 100) / 100,
uptime_pct: toUptimePct(uptime),
incidents: value.incidents,
outage_minutes: 0,
}
......@@ -131,12 +138,15 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] {
}
function toGroupUptimeSeries(group: PerformanceGroup): UptimeDayPoint[] {
return group.series.map((point) => ({
date: new Date(point.ts * 1000).toISOString(),
uptime_pct: Math.round(point.success_rate * 100) / 100,
incidents: point.success_rate < 100 ? 1 : 0,
outage_minutes: 0,
}))
return group.series.map((point) => {
const successRate = toUptimePct(point.success_rate)
return {
date: new Date(point.ts * 1000).toISOString(),
uptime_pct: successRate,
incidents: successRate < 100 ? 1 : 0,
outage_minutes: 0,
}
})
}
function average(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment