优化判断逻辑
This commit is contained in:
@@ -150,6 +150,8 @@ app.post('/api/setup/init', async (req, res) => {
|
|||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
rx_bytes BIGINT UNSIGNED DEFAULT 0,
|
rx_bytes BIGINT UNSIGNED DEFAULT 0,
|
||||||
tx_bytes BIGINT UNSIGNED DEFAULT 0,
|
tx_bytes BIGINT UNSIGNED DEFAULT 0,
|
||||||
|
rx_bandwidth DOUBLE DEFAULT 0,
|
||||||
|
tx_bandwidth DOUBLE DEFAULT 0,
|
||||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
`);
|
`);
|
||||||
@@ -443,31 +445,22 @@ app.get('/api/metrics/overview', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get network traffic history (past 24h in intervals)
|
// Get network traffic history from DB (past 24h)
|
||||||
app.get('/api/metrics/network-history', async (req, res) => {
|
app.get('/api/metrics/network-history', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const [sources] = await db.query('SELECT * FROM prometheus_sources');
|
const [rows] = await db.query('SELECT rx_bandwidth, tx_bandwidth, UNIX_TIMESTAMP(timestamp) as ts FROM traffic_stats WHERE timestamp >= NOW() - INTERVAL 1 DAY ORDER BY ts ASC');
|
||||||
if (sources.length === 0) {
|
|
||||||
|
if (rows.length === 0) {
|
||||||
return res.json({ timestamps: [], rx: [], tx: [] });
|
return res.json({ timestamps: [], rx: [], tx: [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
const allHistories = await Promise.all(sources.map(source =>
|
res.json({
|
||||||
prometheusService.getNetworkHistory(source.url).catch(err => {
|
timestamps: rows.map(r => r.ts * 1000),
|
||||||
console.error(`Error fetching network history from ${source.name}:`, err.message);
|
rx: rows.map(r => r.rx_bandwidth),
|
||||||
return null;
|
tx: rows.map(r => r.tx_bandwidth)
|
||||||
})
|
});
|
||||||
));
|
|
||||||
|
|
||||||
const validHistories = allHistories.filter(h => h !== null);
|
|
||||||
if (validHistories.length === 0) {
|
|
||||||
return res.json({ timestamps: [], rx: [], tx: [] });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge all histories by timestamp
|
|
||||||
const merged = prometheusService.mergeNetworkHistories(validHistories);
|
|
||||||
res.json(merged);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error fetching network history:', err);
|
console.error('Error fetching network history from DB:', err);
|
||||||
res.status(500).json({ error: 'Failed to fetch network history' });
|
res.status(500).json({ error: 'Failed to fetch network history' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -511,32 +504,46 @@ async function recordTrafficStats() {
|
|||||||
const [sources] = await db.query('SELECT * FROM prometheus_sources');
|
const [sources] = await db.query('SELECT * FROM prometheus_sources');
|
||||||
if (sources.length === 0) return;
|
if (sources.length === 0) return;
|
||||||
|
|
||||||
let totalRx = 0;
|
let totalRxBytes = 0;
|
||||||
let totalTx = 0;
|
let totalTxBytes = 0;
|
||||||
|
let totalRxBandwidth = 0;
|
||||||
|
let totalTxBandwidth = 0;
|
||||||
|
|
||||||
const results = await Promise.all(sources.map(async source => {
|
const results = await Promise.all(sources.map(async source => {
|
||||||
try {
|
try {
|
||||||
const [rxRes, txRes] = await Promise.all([
|
const [rxBytesRes, txBytesRes, rxBWRes, txBWRes] = await Promise.all([
|
||||||
prometheusService.query(source.url, 'sum(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"})'),
|
prometheusService.query(source.url, 'sum(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"})'),
|
||||||
prometheusService.query(source.url, 'sum(node_network_transmit_bytes_total{device!~"lo|veth.*|docker.*|br-.*"})')
|
prometheusService.query(source.url, 'sum(node_network_transmit_bytes_total{device!~"lo|veth.*|docker.*|br-.*"})'),
|
||||||
|
prometheusService.query(source.url, 'sum(rate(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[5m]))'),
|
||||||
|
prometheusService.query(source.url, 'sum(rate(node_network_transmit_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[5m]))')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const rx = (rxRes.length > 0) ? parseFloat(rxRes[0].value[1]) : 0;
|
return {
|
||||||
const tx = (txRes.length > 0) ? parseFloat(txRes[0].value[1]) : 0;
|
rxBytes: (rxBytesRes.length > 0) ? parseFloat(rxBytesRes[0].value[1]) : 0,
|
||||||
return { rx, tx };
|
txBytes: (txBytesRes.length > 0) ? parseFloat(txBytesRes[0].value[1]) : 0,
|
||||||
|
rxBW: (rxBWRes.length > 0) ? parseFloat(rxBWRes[0].value[1]) : 0,
|
||||||
|
txBW: (txBWRes.length > 0) ? parseFloat(txBWRes[0].value[1]) : 0
|
||||||
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { rx: 0, tx: 0 };
|
return { rxBytes: 0, txBytes: 0, rxBW: 0, txBW: 0 };
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for (const r of results) {
|
for (const r of results) {
|
||||||
totalRx += r.rx;
|
totalRxBytes += r.rxBytes;
|
||||||
totalTx += r.tx;
|
totalTxBytes += r.txBytes;
|
||||||
|
totalRxBandwidth += r.rxBW;
|
||||||
|
totalTxBandwidth += r.txBW;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalRx > 0 || totalTx > 0) {
|
if (totalRxBytes > 0 || totalTxBytes > 0) {
|
||||||
await db.query('INSERT INTO traffic_stats (rx_bytes, tx_bytes) VALUES (?, ?)', [Math.round(totalRx), Math.round(totalTx)]);
|
await db.query('INSERT INTO traffic_stats (rx_bytes, tx_bytes, rx_bandwidth, tx_bandwidth) VALUES (?, ?, ?, ?)', [
|
||||||
console.log(`[Traffic Recorder] Saved stats: RX=${totalRx}, TX=${totalTx}`);
|
Math.round(totalRxBytes),
|
||||||
|
Math.round(totalTxBytes),
|
||||||
|
totalRxBandwidth,
|
||||||
|
totalTxBandwidth
|
||||||
|
]);
|
||||||
|
console.log(`[Traffic Recorder] Saved stats: BW_RX=${totalRxBandwidth}, BW_TX=${totalTxBandwidth}`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[Traffic Recorder] Error recording stats:', err);
|
console.error('[Traffic Recorder] Error recording stats:', err);
|
||||||
@@ -552,9 +559,14 @@ async function ensureTrafficTable() {
|
|||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
rx_bytes BIGINT UNSIGNED DEFAULT 0,
|
rx_bytes BIGINT UNSIGNED DEFAULT 0,
|
||||||
tx_bytes BIGINT UNSIGNED DEFAULT 0,
|
tx_bytes BIGINT UNSIGNED DEFAULT 0,
|
||||||
|
rx_bandwidth DOUBLE DEFAULT 0,
|
||||||
|
tx_bandwidth DOUBLE DEFAULT 0,
|
||||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
`);
|
`);
|
||||||
|
// Add columns if missing for existing tables
|
||||||
|
try { await db.query('ALTER TABLE traffic_stats ADD COLUMN rx_bandwidth DOUBLE DEFAULT 0'); } catch(e) {}
|
||||||
|
try { await db.query('ALTER TABLE traffic_stats ADD COLUMN tx_bandwidth DOUBLE DEFAULT 0'); } catch(e) {}
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -159,10 +159,10 @@ async function getOverviewMetrics(url, sourceName) {
|
|||||||
query(url, 'node_memory_MemTotal_bytes').catch(() => []),
|
query(url, 'node_memory_MemTotal_bytes').catch(() => []),
|
||||||
// Memory available per instance
|
// Memory available per instance
|
||||||
query(url, 'node_memory_MemAvailable_bytes').catch(() => []),
|
query(url, 'node_memory_MemAvailable_bytes').catch(() => []),
|
||||||
// Disk total per instance (root filesystem)
|
// Disk total per instance (root filesystem + /data)
|
||||||
query(url, 'sum by (instance, job) (node_filesystem_size_bytes{mountpoint="/",fstype!="tmpfs"})').catch(() => []),
|
query(url, 'sum by (instance, job) (node_filesystem_size_bytes{mountpoint=~"/|/data",fstype!="tmpfs"})').catch(() => []),
|
||||||
// Disk free per instance (root filesystem)
|
// Disk free per instance (root filesystem + /data)
|
||||||
query(url, 'sum by (instance, job) (node_filesystem_free_bytes{mountpoint="/",fstype!="tmpfs"})').catch(() => []),
|
query(url, 'sum by (instance, job) (node_filesystem_free_bytes{mountpoint=~"/|/data",fstype!="tmpfs"})').catch(() => []),
|
||||||
// Network receive rate (bytes/sec)
|
// Network receive rate (bytes/sec)
|
||||||
query(url, 'sum by (instance, job) (rate(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[5m]))').catch(() => []),
|
query(url, 'sum by (instance, job) (rate(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[5m]))').catch(() => []),
|
||||||
// Network transmit rate (bytes/sec)
|
// Network transmit rate (bytes/sec)
|
||||||
@@ -171,8 +171,8 @@ async function getOverviewMetrics(url, sourceName) {
|
|||||||
query(url, 'sum by (instance, job) (increase(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[24h]))').catch(() => []),
|
query(url, 'sum by (instance, job) (increase(node_network_receive_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[24h]))').catch(() => []),
|
||||||
// Total traffic transmitted in last 24h
|
// Total traffic transmitted in last 24h
|
||||||
query(url, 'sum by (instance, job) (increase(node_network_transmit_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[24h]))').catch(() => []),
|
query(url, 'sum by (instance, job) (increase(node_network_transmit_bytes_total{device!~"lo|veth.*|docker.*|br-.*"}[24h]))').catch(() => []),
|
||||||
// Up instances
|
// Up instances (at least one successful scrape in last 5m)
|
||||||
query(url, 'up{job=~".*node.*|.*exporter.*"}').catch(() => [])
|
query(url, 'max_over_time(up{job=~".*node.*|.*exporter.*"}[5m])').catch(() => [])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Build per-instance data map
|
// Build per-instance data map
|
||||||
|
|||||||
Reference in New Issue
Block a user