Commit 21636fc1 by CaIon

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

parent 26b6b364
...@@ -60,6 +60,32 @@ function getChartThemeTokens(resolvedTheme: string) { ...@@ -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) // Latency trend chart (24h, multi-group point-line chart)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -173,12 +199,20 @@ export function UptimeTrendChart(props: { ...@@ -173,12 +199,20 @@ export function UptimeTrendChart(props: {
const spec = useMemo(() => { const spec = useMemo(() => {
if (props.series.length === 0) return null if (props.series.length === 0) return null
const data = props.series.map((point) => ({ const rawData = props.series.map((point) => ({
date: formatDayLabel(point.date), date: formatDayLabel(point.date),
uptime: point.uptime_pct, uptime: toUptimeChartValue(point.uptime_pct),
incidents: point.incidents, incidents: point.incidents,
outage: point.outage_minutes, 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 { return {
type: 'line' as const, type: 'line' as const,
...@@ -204,7 +238,9 @@ export function UptimeTrendChart(props: { ...@@ -204,7 +238,9 @@ export function UptimeTrendChart(props: {
}, },
tooltip: { tooltip: {
mark: { mark: {
title: { value: (d: { date: string }) => d.date }, title: {
value: (d: { date: string }) => stripUptimePointSuffix(d.date),
},
content: [ content: [
{ {
key: t('Uptime'), key: t('Uptime'),
...@@ -225,6 +261,8 @@ export function UptimeTrendChart(props: { ...@@ -225,6 +261,8 @@ export function UptimeTrendChart(props: {
{ {
orient: 'bottom', orient: 'bottom',
label: { label: {
formatMethod: (val: number | string) =>
stripUptimePointSuffix(String(val)),
style: { fill: textColor, fontSize: 10 }, style: { fill: textColor, fontSize: 10 },
autoLimit: true, autoLimit: true,
}, },
...@@ -232,8 +270,8 @@ export function UptimeTrendChart(props: { ...@@ -232,8 +270,8 @@ export function UptimeTrendChart(props: {
}, },
{ {
orient: 'left', orient: 'left',
min: 95, min: axisMin,
max: 100, max: UPTIME_AXIS_MAX,
label: { label: {
formatMethod: (val: number | string) => `${val}%`, formatMethod: (val: number | string) => `${val}%`,
style: { fill: textColor, fontSize: 10 }, style: { fill: textColor, fontSize: 10 },
......
...@@ -79,6 +79,12 @@ type PerformanceRow = { ...@@ -79,6 +79,12 @@ type PerformanceRow = {
avg_tps: number 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[]) { function toLatencySeries(groups: PerformanceGroup[]) {
const byTs = new Map<number, number[]>() const byTs = new Map<number, number[]>()
for (const group of groups) { for (const group of groups) {
...@@ -107,8 +113,9 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] { ...@@ -107,8 +113,9 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] {
for (const point of group.series) { for (const point of group.series) {
const current = byTs.get(point.ts) ?? { rates: [], incidents: 0 } const current = byTs.get(point.ts) ?? { rates: [], incidents: 0 }
if (Number.isFinite(point.success_rate)) { if (Number.isFinite(point.success_rate)) {
current.rates.push(point.success_rate) const successRate = toUptimePct(point.success_rate)
if (point.success_rate < 100) current.incidents += 1 current.rates.push(successRate)
if (successRate < 100) current.incidents += 1
} }
byTs.set(point.ts, current) byTs.set(point.ts, current)
} }
...@@ -123,7 +130,7 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] { ...@@ -123,7 +130,7 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] {
: 0 : 0
return { return {
date: new Date(ts * 1000).toISOString(), date: new Date(ts * 1000).toISOString(),
uptime_pct: Math.round(uptime * 100) / 100, uptime_pct: toUptimePct(uptime),
incidents: value.incidents, incidents: value.incidents,
outage_minutes: 0, outage_minutes: 0,
} }
...@@ -131,12 +138,15 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] { ...@@ -131,12 +138,15 @@ function toUptimeSeries(groups: PerformanceGroup[]): UptimeDayPoint[] {
} }
function toGroupUptimeSeries(group: PerformanceGroup): UptimeDayPoint[] { function toGroupUptimeSeries(group: PerformanceGroup): UptimeDayPoint[] {
return group.series.map((point) => ({ return group.series.map((point) => {
date: new Date(point.ts * 1000).toISOString(), const successRate = toUptimePct(point.success_rate)
uptime_pct: Math.round(point.success_rate * 100) / 100, return {
incidents: point.success_rate < 100 ? 1 : 0, date: new Date(point.ts * 1000).toISOString(),
outage_minutes: 0, uptime_pct: successRate,
})) incidents: successRate < 100 ? 1 : 0,
outage_minutes: 0,
}
})
} }
function average( 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