mirror of
https://github.com/woodchen-ink/random-api-go.git
synced 2025-07-18 13:52:02 +08:00
refactor(public): improve metrics loading and display logic
- Updated the metrics API endpoint from '/metrics' to '/api/metrics' for better organization. - Added data validation to ensure the metrics data received is an object, enhancing error handling. - Refactored the updateMetricsDisplay function to dynamically create metric items, improving the display of metrics. - Implemented HTML escaping for metric keys and values to prevent XSS vulnerabilities. - Cleared existing content in the metrics container before updating, ensuring a clean display.
This commit is contained in:
parent
50e6abaa2f
commit
260bddb56b
@ -210,77 +210,53 @@
|
|||||||
|
|
||||||
async function loadMetrics() {
|
async function loadMetrics() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/metrics');
|
const response = await fetch('/api/metrics');
|
||||||
const metrics = await response.json();
|
const data = await response.json();
|
||||||
updateMetricsDisplay(metrics);
|
|
||||||
|
// 添加数据验证
|
||||||
|
if (!data || typeof data !== 'object') {
|
||||||
|
throw new Error('Invalid metrics data received');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMetricsDisplay(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading metrics:', error);
|
console.error('Error loading metrics:', error);
|
||||||
|
document.getElementById('metrics-container').innerHTML =
|
||||||
|
'<p class="error">加载指标数据时出错,请稍后重试</p>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMetricsDisplay(metrics) {
|
function updateMetricsDisplay(metricsData) {
|
||||||
const metricsHtml = `
|
// 确保 metricsData 是有效对象
|
||||||
<div class="metrics-container">
|
if (!metricsData || typeof metricsData !== 'object') {
|
||||||
<div class="metrics-section">
|
console.error('Invalid metrics data');
|
||||||
<h3>基础指标</h3>
|
return;
|
||||||
<div class="metrics-grid">
|
}
|
||||||
<div class="metric-item">运行时间:${formatDuration(metrics?.uptime || 0)}</div>
|
|
||||||
<div class="metric-item">启动时间:${new Date(metrics?.start_time || Date.now()).toLocaleString()}</div>
|
const container = document.getElementById('metrics-container');
|
||||||
</div>
|
container.innerHTML = ''; // 清空现有内容
|
||||||
</div>
|
|
||||||
|
// 使用 Object.entries 之前进行安全检查
|
||||||
<div class="metrics-section">
|
const entries = Object.entries(metricsData).filter(([key, value]) => key && value !== undefined);
|
||||||
<h3>系统指标</h3>
|
|
||||||
<div class="metrics-grid">
|
|
||||||
<div class="metric-item">CPU核心数:${metrics?.num_cpu || 0}</div>
|
|
||||||
<div class="metric-item">Goroutine数:${metrics?.num_goroutine || 0}</div>
|
|
||||||
<div class="metric-item">内存使用:${formatBytes(metrics?.memory_stats?.heap_alloc || 0)}</div>
|
|
||||||
<div class="metric-item">系统内存:${formatBytes(metrics?.memory_stats?.heap_sys || 0)}</div>
|
|
||||||
<div class="metric-item">平均延迟:${formatLatency(metrics?.average_latency || 0)}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="metrics-section">
|
|
||||||
<h3>热门引用来源 (5分钟统计)</h3>
|
|
||||||
<div class="top-referers">
|
|
||||||
${metrics?.top_referers ? Object.entries(metrics.top_referers)
|
|
||||||
.sort(([, a], [, b]) => b - a)
|
|
||||||
.slice(0, 10)
|
|
||||||
.map(([referer, count]) => `
|
|
||||||
<div class="referer-item">
|
|
||||||
<span class="referer">${referer}</span>
|
|
||||||
<span class="count">${count}</span>
|
|
||||||
</div>
|
|
||||||
`).join('') : ''}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const metricsElement = document.getElementById('system-metrics');
|
entries.forEach(([key, value]) => {
|
||||||
if (metricsElement) {
|
const metricDiv = document.createElement('div');
|
||||||
metricsElement.innerHTML = metricsHtml;
|
metricDiv.className = 'metric-item';
|
||||||
}
|
metricDiv.innerHTML = `
|
||||||
|
<h3>${escapeHtml(key)}</h3>
|
||||||
|
<p>${escapeHtml(String(value))}</p>
|
||||||
|
`;
|
||||||
|
container.appendChild(metricDiv);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatBytes(bytes) {
|
function escapeHtml(unsafe) {
|
||||||
const units = ['B', 'KB', 'MB', 'GB'];
|
return unsafe
|
||||||
let size = bytes;
|
.replace(/&/g, "&")
|
||||||
let unitIndex = 0;
|
.replace(/</g, "<")
|
||||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
.replace(/>/g, ">")
|
||||||
size /= 1024;
|
.replace(/"/g, """)
|
||||||
unitIndex++;
|
.replace(/'/g, "'");
|
||||||
}
|
|
||||||
return `${size.toFixed(2)} ${units[unitIndex]}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatDuration(ns) {
|
|
||||||
const duration = ns / 1e9; // 转换为秒
|
|
||||||
const days = Math.floor(duration / 86400);
|
|
||||||
const hours = Math.floor((duration % 86400) / 3600);
|
|
||||||
const minutes = Math.floor((duration % 3600) / 60);
|
|
||||||
const seconds = Math.floor(duration % 60);
|
|
||||||
return `${days}天 ${hours}时 ${minutes}分 ${seconds}秒`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定期更新监控数据
|
// 定期更新监控数据
|
||||||
|
Loading…
x
Reference in New Issue
Block a user