添加更详细的信息查询
This commit is contained in:
@@ -601,6 +601,31 @@ app.get('/api/metrics/cpu-history', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Get detailed metrics for a specific server
|
||||
app.get('/api/metrics/server-details', async (req, res) => {
|
||||
const { instance, job, source } = req.query;
|
||||
|
||||
if (!instance || !job || !source) {
|
||||
return res.status(400).json({ error: 'instance, job, and source name are required' });
|
||||
}
|
||||
|
||||
try {
|
||||
// Find the source URL by name
|
||||
const [rows] = await db.query('SELECT url FROM prometheus_sources WHERE name = ?', [source]);
|
||||
if (rows.length === 0) {
|
||||
return res.status(404).json({ error: 'Prometheus source not found' });
|
||||
}
|
||||
const sourceUrl = rows[0].url;
|
||||
|
||||
// Fetch detailed metrics
|
||||
const details = await prometheusService.getServerDetails(sourceUrl, instance, job);
|
||||
res.json(details);
|
||||
} catch (err) {
|
||||
console.error(`Error fetching server details for ${instance}:`, err.message);
|
||||
res.status(500).json({ error: 'Failed to fetch server details' });
|
||||
}
|
||||
});
|
||||
|
||||
// SPA fallback
|
||||
app.get('*', (req, res, next) => {
|
||||
if (req.path.startsWith('/api/') || req.path.includes('.')) return next();
|
||||
|
||||
@@ -412,6 +412,42 @@ function mergeCpuHistories(histories) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get detailed metrics for a specific server (node)
|
||||
*/
|
||||
async function getServerDetails(baseUrl, instance, job) {
|
||||
const url = normalizeUrl(baseUrl);
|
||||
const node = instance;
|
||||
|
||||
// Queries based on the requested dashboard structure
|
||||
const queries = {
|
||||
cpuBusy: `100 * (1 - avg(rate(node_cpu_seconds_total{mode="idle", instance="${node}"}[1m])))`,
|
||||
sysLoad: `node_load1{instance="${node}",job="${job}"} * 100 / count(count(node_cpu_seconds_total{instance="${node}",job="${job}"}) by (cpu))`,
|
||||
memUsedPct: `(1 - (node_memory_MemAvailable_bytes{instance="${node}", job="${job}"} / node_memory_MemTotal_bytes{instance="${node}", job="${job}"})) * 100`,
|
||||
swapUsedPct: `((node_memory_SwapTotal_bytes{instance="${node}",job="${job}"} - node_memory_SwapFree_bytes{instance="${node}",job="${job}"}) / (node_memory_SwapTotal_bytes{instance="${node}",job="${job}"})) * 100`,
|
||||
rootFsUsedPct: `100 - ((node_filesystem_avail_bytes{instance="${node}",job="${job}",mountpoint="/",fstype!="rootfs"} * 100) / node_filesystem_size_bytes{instance="${node}",job="${job}",mountpoint="/",fstype!="rootfs"})`,
|
||||
cpuCores: `count(count(node_cpu_seconds_total{instance="${node}",job="${job}"}) by (cpu))`,
|
||||
memTotal: `node_memory_MemTotal_bytes{instance="${node}",job="${job}"}`,
|
||||
uptime: `node_time_seconds{instance="${node}",job="${job}"} - node_boot_time_seconds{instance="${node}",job="${job}"}`,
|
||||
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]))`
|
||||
};
|
||||
|
||||
const results = {};
|
||||
const queryPromises = Object.entries(queries).map(async ([key, expr]) => {
|
||||
try {
|
||||
const res = await query(url, expr);
|
||||
results[key] = res.length > 0 ? parseFloat(res[0].value[1]) : 0;
|
||||
} catch (e) {
|
||||
console.error(`[Prometheus] Error querying ${key} for ${node}:`, e.message);
|
||||
results[key] = 0;
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(queryPromises);
|
||||
return results;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
testConnection,
|
||||
query,
|
||||
@@ -420,5 +456,6 @@ module.exports = {
|
||||
getNetworkHistory,
|
||||
mergeNetworkHistories,
|
||||
getCpuHistory,
|
||||
mergeCpuHistories
|
||||
mergeCpuHistories,
|
||||
getServerDetails
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user