添加连接数指标评估
This commit is contained in:
@@ -399,12 +399,13 @@
|
||||
<th class="sortable" data-sort="disk">磁盘 <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="netRx">网络 ↓ <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="netTx">网络 ↑ <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="conntrack">Conntrack <span class="sort-icon"></span></th>
|
||||
<th class="sortable" data-sort="traffic24h">24h 流量 <span class="sort-icon"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="serverTableBody">
|
||||
<tr class="empty-row">
|
||||
<td colspan="9">暂无数据 - 请先配置 Prometheus 数据源</td>
|
||||
<td colspan="10">暂无数据 - 请先配置 Prometheus 数据源</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1408,7 +1408,8 @@
|
||||
</div>` },
|
||||
{ key: 'rootFsUsedPct', label: '根分区使用率 (/)', value: formatPercent(server.diskPercent) },
|
||||
{ key: 'netRx', label: '网络接收速率 (RX)', value: formatBandwidth(server.netRx) },
|
||||
{ key: 'netTx', label: '网络发送速率 (TX)', value: formatBandwidth(server.netTx) }
|
||||
{ key: 'netTx', label: '网络发送速率 (TX)', value: formatBandwidth(server.netTx) },
|
||||
{ key: 'conntrackUsedPct', label: 'Conntrack 占用比例', value: formatPercent(server.conntrackPercent) }
|
||||
];
|
||||
|
||||
metrics.forEach(m => {
|
||||
@@ -1502,6 +1503,10 @@
|
||||
valA = (a.traffic24hRx ?? 0) + (a.traffic24hTx ?? 0);
|
||||
valB = (b.traffic24hRx ?? 0) + (b.traffic24hTx ?? 0);
|
||||
break;
|
||||
case 'conntrack':
|
||||
valA = a.conntrackPercent ?? 0;
|
||||
valB = b.conntrackPercent ?? 0;
|
||||
break;
|
||||
default:
|
||||
valA = (a.job || '').toLowerCase();
|
||||
valB = (b.job || '').toLowerCase();
|
||||
@@ -1627,7 +1632,7 @@
|
||||
if (!servers || servers.length === 0) {
|
||||
dom.serverTableBody.innerHTML = `
|
||||
<tr class="empty-row">
|
||||
<td colspan="9">暂无数据 - 请先配置 Prometheus 数据源</td>
|
||||
<td colspan="10">暂无数据 - 请先配置 Prometheus 数据源</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
@@ -1672,6 +1677,14 @@
|
||||
</td>
|
||||
<td>${formatBandwidth(server.netRx)}</td>
|
||||
<td>${formatBandwidth(server.netTx)}</td>
|
||||
<td>
|
||||
<div class="usage-bar">
|
||||
<div class="usage-bar-track">
|
||||
<div class="usage-bar-fill usage-bar-fill-cpu" style="width: ${Math.min(server.conntrackPercent || 0, 100)}%; background: var(--accent-indigo);"></div>
|
||||
</div>
|
||||
<span>${formatPercent(server.conntrackPercent || 0)}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div style="font-size: 0.85rem; font-weight: 500; color: var(--text-primary);">${formatBytes((server.traffic24hRx || 0) + (server.traffic24hTx || 0))}</div>
|
||||
<div style="font-size: 0.65rem; color: var(--text-muted); margin-top: 2px;">↓${formatBytes(server.traffic24hRx || 0)} / ↑${formatBytes(server.traffic24hTx || 0)}</div>
|
||||
@@ -1790,6 +1803,11 @@
|
||||
{ key: 'netTx', label: '网络发送速率 (TX)', value: formatBandwidth(data.netTx) },
|
||||
{ key: 'sockstatTcp', label: 'TCP 链接数 (Sockstat)', value: data.sockstatTcp.toFixed(0) },
|
||||
{ key: 'sockstatTcpMem', label: 'TCP 内存占用', value: formatBytes(data.sockstatTcpMem) },
|
||||
{ key: 'conntrackUsedPct', label: 'Conntrack 占用比例', value: `
|
||||
<div style="display: flex; align-items: baseline; gap: 8px;">
|
||||
<span style="font-weight: 700; font-size: 1.1rem;">${formatPercent(data.conntrackUsedPct)}</span>
|
||||
<span style="font-size: 0.7rem; color: var(--text-secondary); font-weight: normal;">(${data.conntrackEntries.toFixed(0)} / ${data.conntrackLimit.toFixed(0)})</span>
|
||||
</div>` },
|
||||
{ key: 'networkTrend', label: '网络流量趋势 (24h)', value: '' }
|
||||
];
|
||||
|
||||
@@ -1952,6 +1970,7 @@
|
||||
if (metricKey.includes('Pct') || metricKey === 'cpuBusy') unit = '%';
|
||||
if (metricKey.startsWith('net')) unit = 'B/s';
|
||||
if (metricKey === 'sockstatTcpMem') unit = 'B';
|
||||
if (metricKey === 'conntrackUsedPct') unit = '%';
|
||||
|
||||
if (metricKey === 'networkTrend') {
|
||||
chart = new AreaChart(canvas);
|
||||
@@ -1966,6 +1985,7 @@
|
||||
if (metricKey === 'memUsedPct') chart.totalValue = currentServerDetail.memTotal;
|
||||
if (metricKey === 'swapUsedPct') chart.totalValue = currentServerDetail.swapTotal;
|
||||
if (metricKey === 'rootFsUsedPct') chart.totalValue = currentServerDetail.rootFsTotal;
|
||||
if (metricKey === 'conntrackUsedPct') chart.totalValue = data.conntrackLimit;
|
||||
|
||||
try {
|
||||
const { instance, job, source } = currentServerDetail;
|
||||
|
||||
@@ -211,7 +211,9 @@ async function getOverviewMetrics(url, sourceName) {
|
||||
netTxResult,
|
||||
netRx24hResult,
|
||||
netTx24hResult,
|
||||
targetsResult
|
||||
targetsResult,
|
||||
conntrackEntriesResult,
|
||||
conntrackLimitResult
|
||||
] = await Promise.all([
|
||||
// CPU usage per instance: 1 - avg idle
|
||||
query(url, '100 - (avg by (instance, job) (rate(node_cpu_seconds_total{mode="idle"}[1m])) * 100)').catch(() => []),
|
||||
@@ -234,7 +236,11 @@ async function getOverviewMetrics(url, sourceName) {
|
||||
// 24h Network transmit total (bytes)
|
||||
query(url, 'sum by (instance, job) (increase(node_network_transmit_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[24h]))').catch(() => []),
|
||||
// Targets status from /api/v1/targets
|
||||
getTargets(url).catch(() => [])
|
||||
getTargets(url).catch(() => []),
|
||||
// Conntrack entries
|
||||
query(url, 'node_nf_conntrack_entries').catch(() => []),
|
||||
// Conntrack limits
|
||||
query(url, 'node_nf_conntrack_entries_limit').catch(() => [])
|
||||
]);
|
||||
|
||||
// Fetch 24h detailed traffic using the A*duration logic
|
||||
@@ -270,9 +276,12 @@ async function getOverviewMetrics(url, sourceName) {
|
||||
netTx: 0,
|
||||
traffic24hRx: 0,
|
||||
traffic24hTx: 0,
|
||||
conntrackEntries: 0,
|
||||
conntrackLimit: 0,
|
||||
up: false,
|
||||
memPercent: 0,
|
||||
diskPercent: 0
|
||||
diskPercent: 0,
|
||||
conntrackPercent: 0
|
||||
});
|
||||
}
|
||||
const inst = instances.get(token);
|
||||
@@ -348,6 +357,16 @@ async function getOverviewMetrics(url, sourceName) {
|
||||
inst.traffic24hTx = parseFloat(r.value[1]) || 0;
|
||||
}
|
||||
|
||||
// Parse conntrack
|
||||
for (const r of conntrackEntriesResult) {
|
||||
const inst = getOrCreate(r.metric);
|
||||
inst.conntrackEntries = parseFloat(r.value[1]) || 0;
|
||||
}
|
||||
for (const r of conntrackLimitResult) {
|
||||
const inst = getOrCreate(r.metric);
|
||||
inst.conntrackLimit = parseFloat(r.value[1]) || 0;
|
||||
}
|
||||
|
||||
for (const inst of instances.values()) {
|
||||
if (!inst.up && (inst.cpuPercent > 0 || inst.memTotal > 0)) {
|
||||
inst.up = true;
|
||||
@@ -355,6 +374,7 @@ async function getOverviewMetrics(url, sourceName) {
|
||||
// Calculate percentages on backend
|
||||
inst.memPercent = inst.memTotal > 0 ? (inst.memUsed / inst.memTotal * 100) : 0;
|
||||
inst.diskPercent = inst.diskTotal > 0 ? (inst.diskUsed / inst.diskTotal * 100) : 0;
|
||||
inst.conntrackPercent = inst.conntrackLimit > 0 ? (inst.conntrackEntries / inst.conntrackLimit * 100) : 0;
|
||||
}
|
||||
|
||||
const allInstancesList = Array.from(instances.values());
|
||||
@@ -602,6 +622,9 @@ async function getServerDetails(baseUrl, instance, job, settings = {}) {
|
||||
netTx: `sum(rate(node_network_transmit_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`,
|
||||
sockstatTcp: `node_sockstat_TCP_inuse{instance="${node}",job="${job}"}`,
|
||||
sockstatTcpMem: `node_sockstat_TCP_mem{instance="${node}",job="${job}"} * 4096`,
|
||||
conntrackEntries: `node_nf_conntrack_entries{instance="${node}",job="${job}"}`,
|
||||
conntrackLimit: `node_nf_conntrack_entries_limit{instance="${node}",job="${job}"}`,
|
||||
conntrackUsedPct: `(node_nf_conntrack_entries{instance="${node}",job="${job}"} / node_nf_conntrack_entries_limit{instance="${node}",job="${job}"}) * 100`,
|
||||
// Get individual partitions (excluding virtual and FUSE mounts)
|
||||
partitions_size: `node_filesystem_size_bytes{instance="${node}", job="${job}", fstype!~"tmpfs|autofs|proc|sysfs|fuse.*", mountpoint!~"/tmp.*|/var/lib/docker/.*|/run/.*"}`,
|
||||
partitions_free: `node_filesystem_free_bytes{instance="${node}", job="${job}", fstype!~"tmpfs|autofs|proc|sysfs|fuse.*", mountpoint!~"/tmp.*|/var/lib/docker/.*|/run/.*"}`
|
||||
@@ -771,7 +794,8 @@ async function getServerHistory(baseUrl, instance, job, metric, range = '1h', st
|
||||
netRx: `sum(rate(node_network_receive_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`,
|
||||
netTx: `sum(rate(node_network_transmit_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`,
|
||||
sockstatTcp: `node_sockstat_TCP_inuse{instance="${node}",job="${job}"}`,
|
||||
sockstatTcpMem: `node_sockstat_TCP_mem{instance="${node}",job="${job}"} * 4096`
|
||||
sockstatTcpMem: `node_sockstat_TCP_mem{instance="${node}",job="${job}"} * 4096`,
|
||||
conntrackUsedPct: `(node_nf_conntrack_entries{instance="${node}",job="${job}"} / node_nf_conntrack_entries_limit{instance="${node}",job="${job}"}) * 100`
|
||||
};
|
||||
|
||||
const rangeObj = parseRange(range, start, end);
|
||||
|
||||
Reference in New Issue
Block a user