加入自定义指标支持
This commit is contained in:
@@ -66,6 +66,8 @@ const SCHEMA = {
|
||||
ps_filing VARCHAR(255),
|
||||
network_data_sources TEXT,
|
||||
show_server_ip TINYINT(1) DEFAULT 0,
|
||||
ip_metric_name VARCHAR(100) DEFAULT NULL,
|
||||
ip_label_name VARCHAR(100) DEFAULT 'address',
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`,
|
||||
@@ -132,6 +134,14 @@ const SCHEMA = {
|
||||
{
|
||||
name: 'show_server_ip',
|
||||
sql: "ALTER TABLE site_settings ADD COLUMN show_server_ip TINYINT(1) DEFAULT 0 AFTER network_data_sources"
|
||||
},
|
||||
{
|
||||
name: 'ip_metric_name',
|
||||
sql: "ALTER TABLE site_settings ADD COLUMN ip_metric_name VARCHAR(100) DEFAULT NULL AFTER show_server_ip"
|
||||
},
|
||||
{
|
||||
name: 'ip_label_name',
|
||||
sql: "ALTER TABLE site_settings ADD COLUMN ip_label_name VARCHAR(100) DEFAULT 'address' AFTER ip_metric_name"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -146,7 +146,9 @@ function getPublicSiteSettings(settings = {}) {
|
||||
icp_filing: settings.icp_filing || null,
|
||||
ps_filing: settings.ps_filing || null,
|
||||
network_data_sources: settings.network_data_sources || null,
|
||||
show_server_ip: settings.show_server_ip ? 1 : 0
|
||||
show_server_ip: settings.show_server_ip ? 1 : 0,
|
||||
ip_metric_name: settings.ip_metric_name || null,
|
||||
ip_label_name: settings.ip_label_name || 'address'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -551,6 +553,8 @@ app.post('/api/setup/init', ensureSetupAccess, async (req, res) => {
|
||||
ps_filing VARCHAR(255),
|
||||
network_data_sources TEXT,
|
||||
show_server_ip TINYINT(1) DEFAULT 0,
|
||||
ip_metric_name VARCHAR(100) DEFAULT NULL,
|
||||
ip_label_name VARCHAR(100) DEFAULT 'address',
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
@@ -566,6 +570,8 @@ app.post('/api/setup/init', ensureSetupAccess, async (req, res) => {
|
||||
await connection.query("ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS require_login_for_server_details TINYINT(1) DEFAULT 1 AFTER p95_type");
|
||||
await connection.query("ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS network_data_sources TEXT AFTER ps_filing");
|
||||
await connection.query("ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS show_server_ip TINYINT(1) DEFAULT 0 AFTER network_data_sources");
|
||||
await connection.query("ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS ip_metric_name VARCHAR(100) DEFAULT NULL AFTER show_server_ip");
|
||||
await connection.query("ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS ip_label_name VARCHAR(100) DEFAULT 'address' AFTER ip_metric_name");
|
||||
await connection.query(`
|
||||
CREATE TABLE IF NOT EXISTS latency_routes (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -923,7 +929,9 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
||||
icp_filing: icp_filing !== undefined ? icp_filing : (current.icp_filing || null),
|
||||
ps_filing: ps_filing !== undefined ? ps_filing : (current.ps_filing || null),
|
||||
network_data_sources: network_data_sources !== undefined ? network_data_sources : (current.network_data_sources || null),
|
||||
show_server_ip: show_server_ip !== undefined ? (show_server_ip ? 1 : 0) : (current.show_server_ip || 0)
|
||||
show_server_ip: show_server_ip !== undefined ? (show_server_ip ? 1 : 0) : (current.show_server_ip || 0),
|
||||
ip_metric_name: ip_metric_name !== undefined ? ip_metric_name : (current.ip_metric_name || null),
|
||||
ip_label_name: ip_label_name !== undefined ? ip_label_name : (current.ip_label_name || 'address')
|
||||
};
|
||||
|
||||
await db.query(`
|
||||
@@ -1216,8 +1224,8 @@ app.get('/api/metrics/server-details', requireServerDetailsAccess, async (req, r
|
||||
}
|
||||
const sourceUrl = rows[0].url;
|
||||
|
||||
// Fetch detailed metrics
|
||||
const details = await prometheusService.getServerDetails(sourceUrl, instance, job);
|
||||
// Fetch detailed metrics with custom metric configuration if present
|
||||
const details = await prometheusService.getServerDetails(sourceUrl, instance, job, req.siteSettings);
|
||||
|
||||
// Dynamic field removal based on security settings: PHYSICAL DATA STRIPPING
|
||||
if (!req.siteSettings || !req.siteSettings.show_server_ip) {
|
||||
|
||||
@@ -535,7 +535,7 @@ function resolveToken(token) {
|
||||
/**
|
||||
* Get detailed metrics for a specific server (node)
|
||||
*/
|
||||
async function getServerDetails(baseUrl, instance, job) {
|
||||
async function getServerDetails(baseUrl, instance, job, settings = {}) {
|
||||
const url = normalizeUrl(baseUrl);
|
||||
const node = resolveToken(instance);
|
||||
|
||||
@@ -582,12 +582,38 @@ async function getServerDetails(baseUrl, instance, job) {
|
||||
|
||||
await Promise.all(queryPromises);
|
||||
|
||||
// Add IP information from Prometheus target (discovered labels or scrape URL)
|
||||
// Add IP information
|
||||
try {
|
||||
let foundIp = false;
|
||||
|
||||
// 1. Try Custom Node Exporter Metric if configured
|
||||
if (settings.ip_metric_name) {
|
||||
try {
|
||||
const expr = `${settings.ip_metric_name}{instance="${node}",job="${job}"}`;
|
||||
const res = await query(url, expr);
|
||||
if (res && res.length > 0) {
|
||||
const address = res[0].metric[settings.ip_label_name || 'address'];
|
||||
if (address) {
|
||||
if (address.includes(':')) {
|
||||
results.ipv6 = [address];
|
||||
results.ipv4 = [];
|
||||
} else {
|
||||
results.ipv4 = [address];
|
||||
results.ipv6 = [];
|
||||
}
|
||||
foundIp = true;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`[Prometheus] Error querying custom IP metric ${settings.ip_metric_name}:`, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to Prometheus Targets API
|
||||
if (!foundIp) {
|
||||
const targets = await getTargets(baseUrl);
|
||||
const matchedTarget = targets.find(t => t.labels && t.labels.instance === node && t.labels.job === job);
|
||||
if (matchedTarget) {
|
||||
// Extract address from scrapeUrl or instance label
|
||||
const scrapeUrl = matchedTarget.scrapeUrl || '';
|
||||
try {
|
||||
const urlObj = new URL(scrapeUrl);
|
||||
@@ -599,20 +625,29 @@ async function getServerDetails(baseUrl, instance, job) {
|
||||
results.ipv4 = [host];
|
||||
results.ipv6 = [];
|
||||
}
|
||||
foundIp = true;
|
||||
} catch (e) {
|
||||
// Fallback to instance label without port
|
||||
const inst = matchedTarget.labels.instance.split(':')[0];
|
||||
results.ipv4 = [inst];
|
||||
results.ipv6 = [];
|
||||
results.ipv4 = [];
|
||||
results.ipv6 = [];
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
results.ipv4 = [];
|
||||
results.ipv6 = [];
|
||||
}
|
||||
} else {
|
||||
results.ipv4 = [];
|
||||
results.ipv6 = [];
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`[Prometheus] Error fetching target info for ${node}:`, e.message);
|
||||
}
|
||||
|
||||
if (!foundIp) {
|
||||
results.ipv4 = [];
|
||||
results.ipv6 = [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`[Prometheus] Critical error resolving IPs for ${node}:`, err.message);
|
||||
results.ipv4 = [];
|
||||
results.ipv6 = [];
|
||||
}
|
||||
|
||||
// Group partitions
|
||||
|
||||
Reference in New Issue
Block a user