增加系统版本维护页面
This commit is contained in:
parent
2d08651f62
commit
ef7efe0497
@ -188,9 +188,40 @@ const MetricsDashboard: React.FC = () => {
|
|||||||
process: formatPercent(metrics.cpu.processCpu * 100) + '%',
|
process: formatPercent(metrics.cpu.processCpu * 100) + '%',
|
||||||
},
|
},
|
||||||
memory: {
|
memory: {
|
||||||
heapUsed: formatBytes(metrics.memory.heapUsed),
|
heap: {
|
||||||
heapMax: formatBytes(metrics.memory.heapMax),
|
used: formatBytes(metrics.memory.heapUsed),
|
||||||
heapPercent: formatPercent(metrics.memory.heapPercent) + '%',
|
max: formatBytes(metrics.memory.heapMax),
|
||||||
|
committed: formatBytes(metrics.memory.heapCommitted),
|
||||||
|
percent: formatPercent(metrics.memory.heapPercent) + '%',
|
||||||
|
},
|
||||||
|
nonHeap: {
|
||||||
|
used: formatBytes(metrics.memory.nonHeapUsed),
|
||||||
|
max: formatBytes(metrics.memory.nonHeapMax),
|
||||||
|
committed: formatBytes(metrics.memory.nonHeapCommitted),
|
||||||
|
percent: formatPercent(metrics.memory.nonHeapPercent) + '%',
|
||||||
|
},
|
||||||
|
regions: metrics.memory.regions ? {
|
||||||
|
eden: metrics.memory.regions.eden ? {
|
||||||
|
used: formatBytes(metrics.memory.regions.eden.used),
|
||||||
|
max: formatBytes(metrics.memory.regions.eden.max),
|
||||||
|
committed: formatBytes(metrics.memory.regions.eden.committed),
|
||||||
|
} : null,
|
||||||
|
oldGen: metrics.memory.regions.oldGen ? {
|
||||||
|
used: formatBytes(metrics.memory.regions.oldGen.used),
|
||||||
|
max: formatBytes(metrics.memory.regions.oldGen.max),
|
||||||
|
committed: formatBytes(metrics.memory.regions.oldGen.committed),
|
||||||
|
} : null,
|
||||||
|
survivor: metrics.memory.regions.survivor ? {
|
||||||
|
used: formatBytes(metrics.memory.regions.survivor.used),
|
||||||
|
max: formatBytes(metrics.memory.regions.survivor.max),
|
||||||
|
committed: formatBytes(metrics.memory.regions.survivor.committed),
|
||||||
|
} : null,
|
||||||
|
metaspace: metrics.memory.regions.metaspace ? {
|
||||||
|
used: formatBytes(metrics.memory.regions.metaspace.used),
|
||||||
|
max: formatBytes(metrics.memory.regions.metaspace.max),
|
||||||
|
committed: formatBytes(metrics.memory.regions.metaspace.committed),
|
||||||
|
} : null,
|
||||||
|
} : null,
|
||||||
},
|
},
|
||||||
threads: metrics.threads,
|
threads: metrics.threads,
|
||||||
hikari: metrics.hikari,
|
hikari: metrics.hikari,
|
||||||
@ -350,8 +381,9 @@ const MetricsDashboard: React.FC = () => {
|
|||||||
<div className={`text-2xl font-bold ${getStatusColor(memoryPercent, THRESHOLDS.memory)}`}>
|
<div className={`text-2xl font-bold ${getStatusColor(memoryPercent, THRESHOLDS.memory)}`}>
|
||||||
{formatBytes(metrics.memory.heapUsed)}
|
{formatBytes(metrics.memory.heapUsed)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-muted-foreground">
|
<div className="text-xs text-muted-foreground space-y-0.5">
|
||||||
/ {formatBytes(metrics.memory.heapMax)}
|
<div>最大: {formatBytes(metrics.memory.heapMax)}</div>
|
||||||
|
<div>已分配: {formatBytes(metrics.memory.heapCommitted)}</div>
|
||||||
</div>
|
</div>
|
||||||
<Progress value={memoryPercent} className="h-2" />
|
<Progress value={memoryPercent} className="h-2" />
|
||||||
{memoryPercent >= THRESHOLDS.memory.warning && (
|
{memoryPercent >= THRESHOLDS.memory.warning && (
|
||||||
@ -549,6 +581,118 @@ const MetricsDashboard: React.FC = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 内存区域详情(如果可用) */}
|
||||||
|
{metrics.memory.regions && (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>JVM 内存区域详情</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||||
|
{/* Eden 区 */}
|
||||||
|
{metrics.memory.regions.eden && (
|
||||||
|
<div className="p-4 bg-gradient-to-br from-green-50 to-emerald-50 dark:from-green-950/20 dark:to-emerald-950/20 rounded-lg border border-green-200 dark:border-green-900">
|
||||||
|
<div className="text-sm font-medium text-muted-foreground mb-2">Eden 区(年轻代)</div>
|
||||||
|
<div className="space-y-1 text-xs">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">已使用:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.eden.used)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">已分配:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.eden.committed)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">最大:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.eden.max)}</span>
|
||||||
|
</div>
|
||||||
|
<Progress
|
||||||
|
value={(metrics.memory.regions.eden.used / metrics.memory.regions.eden.max) * 100}
|
||||||
|
className="h-1 mt-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Old Gen */}
|
||||||
|
{metrics.memory.regions.oldGen && (
|
||||||
|
<div className="p-4 bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-blue-950/20 dark:to-indigo-950/20 rounded-lg border border-blue-200 dark:border-blue-900">
|
||||||
|
<div className="text-sm font-medium text-muted-foreground mb-2">Old Gen(老年代)</div>
|
||||||
|
<div className="space-y-1 text-xs">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">已使用:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.oldGen.used)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">已分配:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.oldGen.committed)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">最大:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.oldGen.max)}</span>
|
||||||
|
</div>
|
||||||
|
<Progress
|
||||||
|
value={(metrics.memory.regions.oldGen.used / metrics.memory.regions.oldGen.max) * 100}
|
||||||
|
className="h-1 mt-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Survivor 区 */}
|
||||||
|
{metrics.memory.regions.survivor && (
|
||||||
|
<div className="p-4 bg-gradient-to-br from-yellow-50 to-orange-50 dark:from-yellow-950/20 dark:to-orange-950/20 rounded-lg border border-yellow-200 dark:border-yellow-900">
|
||||||
|
<div className="text-sm font-medium text-muted-foreground mb-2">Survivor 区</div>
|
||||||
|
<div className="space-y-1 text-xs">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">已使用:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.survivor.used)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">已分配:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.survivor.committed)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">最大:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.survivor.max)}</span>
|
||||||
|
</div>
|
||||||
|
<Progress
|
||||||
|
value={(metrics.memory.regions.survivor.used / metrics.memory.regions.survivor.max) * 100}
|
||||||
|
className="h-1 mt-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Metaspace */}
|
||||||
|
{metrics.memory.regions.metaspace && (
|
||||||
|
<div className="p-4 bg-gradient-to-br from-purple-50 to-pink-50 dark:from-purple-950/20 dark:to-pink-950/20 rounded-lg border border-purple-200 dark:border-purple-900">
|
||||||
|
<div className="text-sm font-medium text-muted-foreground mb-2">Metaspace(元空间)</div>
|
||||||
|
<div className="space-y-1 text-xs">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">已使用:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.metaspace.used)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">已分配:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.metaspace.committed)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">最大:</span>
|
||||||
|
<span className="font-medium">{formatBytes(metrics.memory.regions.metaspace.max)}</span>
|
||||||
|
</div>
|
||||||
|
<Progress
|
||||||
|
value={(metrics.memory.regions.metaspace.used / metrics.memory.regions.metaspace.max) * 100}
|
||||||
|
className="h-1 mt-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* GC 统计 */}
|
{/* GC 统计 */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@ -42,28 +42,95 @@ export const getMetric = (metricName: string, tag?: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 JVM 内存信息
|
* 获取 JVM 内存信息(增强版:包含 committed 和区域详情)
|
||||||
*/
|
*/
|
||||||
export const getJvmMemory = async (): Promise<JvmMemoryInfo> => {
|
export const getJvmMemory = async (): Promise<JvmMemoryInfo> => {
|
||||||
const [heapUsedRes, heapMaxRes, nonHeapUsedRes, nonHeapMaxRes] = await Promise.all([
|
// 基础堆和非堆内存指标
|
||||||
|
const [
|
||||||
|
heapUsedRes,
|
||||||
|
heapMaxRes,
|
||||||
|
heapCommittedRes,
|
||||||
|
nonHeapUsedRes,
|
||||||
|
nonHeapMaxRes,
|
||||||
|
nonHeapCommittedRes
|
||||||
|
] = await Promise.all([
|
||||||
getMetric('jvm.memory.used', 'area:heap'),
|
getMetric('jvm.memory.used', 'area:heap'),
|
||||||
getMetric('jvm.memory.max', 'area:heap'),
|
getMetric('jvm.memory.max', 'area:heap'),
|
||||||
|
getMetric('jvm.memory.committed', 'area:heap'),
|
||||||
getMetric('jvm.memory.used', 'area:nonheap'),
|
getMetric('jvm.memory.used', 'area:nonheap'),
|
||||||
getMetric('jvm.memory.max', 'area:nonheap'),
|
getMetric('jvm.memory.max', 'area:nonheap'),
|
||||||
|
getMetric('jvm.memory.committed', 'area:nonheap'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const heapUsed = heapUsedRes.measurements[0].value;
|
const heapUsed = heapUsedRes.measurements[0].value;
|
||||||
const heapMax = heapMaxRes.measurements[0].value;
|
const heapMax = heapMaxRes.measurements[0].value;
|
||||||
|
const heapCommitted = heapCommittedRes.measurements[0].value;
|
||||||
const nonHeapUsed = nonHeapUsedRes.measurements[0].value;
|
const nonHeapUsed = nonHeapUsedRes.measurements[0].value;
|
||||||
const nonHeapMax = nonHeapMaxRes.measurements[0].value;
|
const nonHeapMax = nonHeapMaxRes.measurements[0].value;
|
||||||
|
const nonHeapCommitted = nonHeapCommittedRes.measurements[0].value;
|
||||||
|
|
||||||
|
// 尝试获取详细区域信息(可能因GC类型不同而失败)
|
||||||
|
let regions;
|
||||||
|
try {
|
||||||
|
const [edenUsed, edenMax, edenCommitted, oldUsed, oldMax, oldCommitted,
|
||||||
|
survivorUsed, survivorMax, survivorCommitted, metaspaceUsed, metaspaceMax, metaspaceCommitted] =
|
||||||
|
await Promise.all([
|
||||||
|
// Eden 区
|
||||||
|
getMetric('jvm.memory.used', 'id:G1 Eden Space').catch(() => null),
|
||||||
|
getMetric('jvm.memory.max', 'id:G1 Eden Space').catch(() => null),
|
||||||
|
getMetric('jvm.memory.committed', 'id:G1 Eden Space').catch(() => null),
|
||||||
|
// Old Gen
|
||||||
|
getMetric('jvm.memory.used', 'id:G1 Old Gen').catch(() => null),
|
||||||
|
getMetric('jvm.memory.max', 'id:G1 Old Gen').catch(() => null),
|
||||||
|
getMetric('jvm.memory.committed', 'id:G1 Old Gen').catch(() => null),
|
||||||
|
// Survivor
|
||||||
|
getMetric('jvm.memory.used', 'id:G1 Survivor Space').catch(() => null),
|
||||||
|
getMetric('jvm.memory.max', 'id:G1 Survivor Space').catch(() => null),
|
||||||
|
getMetric('jvm.memory.committed', 'id:G1 Survivor Space').catch(() => null),
|
||||||
|
// Metaspace
|
||||||
|
getMetric('jvm.memory.used', 'id:Metaspace').catch(() => null),
|
||||||
|
getMetric('jvm.memory.max', 'id:Metaspace').catch(() => null),
|
||||||
|
getMetric('jvm.memory.committed', 'id:Metaspace').catch(() => null),
|
||||||
|
]);
|
||||||
|
|
||||||
|
regions = {
|
||||||
|
eden: edenUsed && edenMax && edenCommitted ? {
|
||||||
|
used: edenUsed.measurements[0].value,
|
||||||
|
max: edenMax.measurements[0].value,
|
||||||
|
committed: edenCommitted.measurements[0].value,
|
||||||
|
} : undefined,
|
||||||
|
oldGen: oldUsed && oldMax && oldCommitted ? {
|
||||||
|
used: oldUsed.measurements[0].value,
|
||||||
|
max: oldMax.measurements[0].value,
|
||||||
|
committed: oldCommitted.measurements[0].value,
|
||||||
|
} : undefined,
|
||||||
|
survivor: survivorUsed && survivorMax && survivorCommitted ? {
|
||||||
|
used: survivorUsed.measurements[0].value,
|
||||||
|
max: survivorMax.measurements[0].value,
|
||||||
|
committed: survivorCommitted.measurements[0].value,
|
||||||
|
} : undefined,
|
||||||
|
metaspace: metaspaceUsed && metaspaceMax && metaspaceCommitted ? {
|
||||||
|
used: metaspaceUsed.measurements[0].value,
|
||||||
|
max: metaspaceMax.measurements[0].value,
|
||||||
|
committed: metaspaceCommitted.measurements[0].value,
|
||||||
|
} : undefined,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
// 如果区域详情获取失败(可能是非G1 GC),忽略错误
|
||||||
|
console.debug('无法获取内存区域详情,可能使用了非G1 GC收集器');
|
||||||
|
regions = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
heapUsed,
|
heapUsed,
|
||||||
heapMax,
|
heapMax,
|
||||||
|
heapCommitted,
|
||||||
heapPercent: (heapUsed / heapMax) * 100,
|
heapPercent: (heapUsed / heapMax) * 100,
|
||||||
nonHeapUsed,
|
nonHeapUsed,
|
||||||
nonHeapMax,
|
nonHeapMax,
|
||||||
|
nonHeapCommitted,
|
||||||
nonHeapPercent: (nonHeapUsed / nonHeapMax) * 100,
|
nonHeapPercent: (nonHeapUsed / nonHeapMax) * 100,
|
||||||
|
regions,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -232,9 +299,11 @@ export const getAllMetrics = async (): Promise<SystemMetrics> => {
|
|||||||
memory: memoryResult.status === 'fulfilled' ? memoryResult.value : {
|
memory: memoryResult.status === 'fulfilled' ? memoryResult.value : {
|
||||||
heapUsed: 0,
|
heapUsed: 0,
|
||||||
heapMax: 0,
|
heapMax: 0,
|
||||||
|
heapCommitted: 0,
|
||||||
heapPercent: 0,
|
heapPercent: 0,
|
||||||
nonHeapUsed: 0,
|
nonHeapUsed: 0,
|
||||||
nonHeapMax: 0,
|
nonHeapMax: 0,
|
||||||
|
nonHeapCommitted: 0,
|
||||||
nonHeapPercent: 0,
|
nonHeapPercent: 0,
|
||||||
},
|
},
|
||||||
cpu: cpuResult.status === 'fulfilled' ? cpuResult.value : { systemCpu: 0, processCpu: 0 },
|
cpu: cpuResult.status === 'fulfilled' ? cpuResult.value : { systemCpu: 0, processCpu: 0 },
|
||||||
|
|||||||
@ -49,16 +49,34 @@ export interface MetricResponse {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JVM 内存区域详情
|
||||||
|
*/
|
||||||
|
export interface MemoryRegion {
|
||||||
|
used: number; // 已使用(字节)
|
||||||
|
max: number; // 最大值(字节)
|
||||||
|
committed: number; // 已分配(字节)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JVM 内存信息
|
* JVM 内存信息
|
||||||
*/
|
*/
|
||||||
export interface JvmMemoryInfo {
|
export interface JvmMemoryInfo {
|
||||||
heapUsed: number; // 堆内存使用量(字节)
|
heapUsed: number; // 堆内存使用量(字节)
|
||||||
heapMax: number; // 堆内存最大值(字节)
|
heapMax: number; // 堆内存最大值(字节)
|
||||||
|
heapCommitted: number; // 堆内存已分配(字节)
|
||||||
heapPercent: number; // 堆内存使用百分比
|
heapPercent: number; // 堆内存使用百分比
|
||||||
nonHeapUsed: number; // 非堆内存使用量(字节)
|
nonHeapUsed: number; // 非堆内存使用量(字节)
|
||||||
nonHeapMax: number; // 非堆内存最大值(字节)
|
nonHeapMax: number; // 非堆内存最大值(字节)
|
||||||
|
nonHeapCommitted: number; // 非堆内存已分配(字节)
|
||||||
nonHeapPercent: number; // 非堆内存使用百分比
|
nonHeapPercent: number; // 非堆内存使用百分比
|
||||||
|
// 详细区域信息(可选)
|
||||||
|
regions?: {
|
||||||
|
eden?: MemoryRegion; // Eden 区(年轻代)
|
||||||
|
oldGen?: MemoryRegion; // Old Gen(老年代)
|
||||||
|
survivor?: MemoryRegion; // Survivor 区
|
||||||
|
metaspace?: MemoryRegion; // Metaspace(元空间)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user