增加系统版本维护页面
This commit is contained in:
parent
2d08651f62
commit
ef7efe0497
@ -188,9 +188,40 @@ const MetricsDashboard: React.FC = () => {
|
||||
process: formatPercent(metrics.cpu.processCpu * 100) + '%',
|
||||
},
|
||||
memory: {
|
||||
heapUsed: formatBytes(metrics.memory.heapUsed),
|
||||
heapMax: formatBytes(metrics.memory.heapMax),
|
||||
heapPercent: formatPercent(metrics.memory.heapPercent) + '%',
|
||||
heap: {
|
||||
used: formatBytes(metrics.memory.heapUsed),
|
||||
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,
|
||||
hikari: metrics.hikari,
|
||||
@ -350,8 +381,9 @@ const MetricsDashboard: React.FC = () => {
|
||||
<div className={`text-2xl font-bold ${getStatusColor(memoryPercent, THRESHOLDS.memory)}`}>
|
||||
{formatBytes(metrics.memory.heapUsed)}
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
/ {formatBytes(metrics.memory.heapMax)}
|
||||
<div className="text-xs text-muted-foreground space-y-0.5">
|
||||
<div>最大: {formatBytes(metrics.memory.heapMax)}</div>
|
||||
<div>已分配: {formatBytes(metrics.memory.heapCommitted)}</div>
|
||||
</div>
|
||||
<Progress value={memoryPercent} className="h-2" />
|
||||
{memoryPercent >= THRESHOLDS.memory.warning && (
|
||||
@ -549,6 +581,118 @@ const MetricsDashboard: React.FC = () => {
|
||||
</Card>
|
||||
</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 统计 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
||||
@ -42,28 +42,95 @@ export const getMetric = (metricName: string, tag?: string) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取 JVM 内存信息
|
||||
* 获取 JVM 内存信息(增强版:包含 committed 和区域详情)
|
||||
*/
|
||||
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.max', 'area:heap'),
|
||||
getMetric('jvm.memory.committed', 'area:heap'),
|
||||
getMetric('jvm.memory.used', 'area:nonheap'),
|
||||
getMetric('jvm.memory.max', 'area:nonheap'),
|
||||
getMetric('jvm.memory.committed', 'area:nonheap'),
|
||||
]);
|
||||
|
||||
const heapUsed = heapUsedRes.measurements[0].value;
|
||||
const heapMax = heapMaxRes.measurements[0].value;
|
||||
const heapCommitted = heapCommittedRes.measurements[0].value;
|
||||
const nonHeapUsed = nonHeapUsedRes.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 {
|
||||
heapUsed,
|
||||
heapMax,
|
||||
heapCommitted,
|
||||
heapPercent: (heapUsed / heapMax) * 100,
|
||||
nonHeapUsed,
|
||||
nonHeapMax,
|
||||
nonHeapCommitted,
|
||||
nonHeapPercent: (nonHeapUsed / nonHeapMax) * 100,
|
||||
regions,
|
||||
};
|
||||
};
|
||||
|
||||
@ -232,9 +299,11 @@ export const getAllMetrics = async (): Promise<SystemMetrics> => {
|
||||
memory: memoryResult.status === 'fulfilled' ? memoryResult.value : {
|
||||
heapUsed: 0,
|
||||
heapMax: 0,
|
||||
heapCommitted: 0,
|
||||
heapPercent: 0,
|
||||
nonHeapUsed: 0,
|
||||
nonHeapMax: 0,
|
||||
nonHeapCommitted: 0,
|
||||
nonHeapPercent: 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 内存信息
|
||||
*/
|
||||
export interface JvmMemoryInfo {
|
||||
heapUsed: number; // 堆内存使用量(字节)
|
||||
heapMax: number; // 堆内存最大值(字节)
|
||||
heapCommitted: number; // 堆内存已分配(字节)
|
||||
heapPercent: number; // 堆内存使用百分比
|
||||
nonHeapUsed: number; // 非堆内存使用量(字节)
|
||||
nonHeapMax: number; // 非堆内存最大值(字节)
|
||||
nonHeapCommitted: 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