diff --git a/internal/handler/metrics.go b/internal/handler/metrics.go
index e3506c3..d9f882c 100644
--- a/internal/handler/metrics.go
+++ b/internal/handler/metrics.go
@@ -293,6 +293,31 @@ var metricsTemplate = `
right: 140px;
color: #666;
}
+ /* 添加表格样式 */
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 10px 0;
+ }
+ th, td {
+ padding: 8px;
+ text-align: left;
+ border-bottom: 1px solid #eee;
+ }
+ th {
+ background: #f8f9fa;
+ color: #666;
+ }
+ .status-badge {
+ padding: 3px 8px;
+ border-radius: 12px;
+ font-size: 12px;
+ color: white;
+ }
+ .status-2xx { background: #28a745; }
+ .status-3xx { background: #17a2b8; }
+ .status-4xx { background: #ffc107; }
+ .status-5xx { background: #dc3545; }
@@ -346,6 +371,56 @@ var metricsTemplate = `
+
+
流量统计
+
+ 总传输字节
+
+
+
+ 每秒传输
+
+
+
+
+
+
+
+
热门路径 (Top 10)
+
+
+
+ 路径 |
+ 请求数 |
+ 错误数 |
+ 平均延迟 |
+ 传输大小 |
+
+
+
+
+
+
+
+
最近请求
+
+
+
+ 时间 |
+ 路径 |
+ 状态 |
+ 延迟 |
+ 大小 |
+ 客户端IP |
+
+
+
+
+
+
@@ -356,6 +431,77 @@ var metricsTemplate = `
window.location.href = '/metrics/ui';
}
+ function formatBytes(bytes) {
+ if (bytes === 0) return '0 B';
+ const k = 1024;
+ const sizes = ['B', 'KB', 'MB', 'GB'];
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+ }
+
+ function formatDate(dateStr) {
+ const date = new Date(dateStr);
+ return date.toLocaleTimeString();
+ }
+
+ function updateMetrics(data) {
+ // 更新现有指标
+ document.getElementById('uptime').textContent = data.uptime;
+ document.getElementById('activeRequests').textContent = data.active_requests;
+ document.getElementById('totalRequests').textContent = data.total_requests;
+ document.getElementById('totalErrors').textContent = data.total_errors;
+ document.getElementById('errorRate').textContent = (data.error_rate * 100).toFixed(2) + '%';
+ document.getElementById('numGoroutine').textContent = data.num_goroutine;
+ document.getElementById('memoryUsage').textContent = data.memory_usage;
+ document.getElementById('avgResponseTime').textContent = data.avg_response_time;
+ document.getElementById('requestsPerSecond').textContent = data.requests_per_second.toFixed(2);
+
+ // 更新流量统计
+ document.getElementById('totalBytes').textContent = formatBytes(data.total_bytes);
+ document.getElementById('bytesPerSecond').textContent = formatBytes(data.bytes_per_second) + '/s';
+
+ // 更新状态码统计
+ const statusCodesHtml = Object.entries(data.status_code_stats)
+ .map(([status, count]) => {
+ const statusClass = 'status-' + status.charAt(0) + 'xx';
+ return '' +
+ '' +
+ '' + status + '' +
+ '' +
+ '' + count + '' +
+ '
';
+ })
+ .join('');
+ document.getElementById('statusCodes').innerHTML = statusCodesHtml;
+
+ // 更新热门路径
+ const topPathsHtml = data.top_paths.map(path =>
+ '' +
+ '' + path.path + ' | ' +
+ '' + path.request_count + ' | ' +
+ '' + path.error_count + ' | ' +
+ '' + path.avg_latency + ' | ' +
+ '' + formatBytes(path.bytes_transferred) + ' | ' +
+ '
'
+ ).join('');
+ document.querySelector('#topPaths tbody').innerHTML = topPathsHtml;
+
+ // 更新最近请求
+ const recentRequestsHtml = data.recent_requests.map(req =>
+ '' +
+ '' + formatDate(req.Time) + ' | ' +
+ '' + req.Path + ' | ' +
+ '' + req.Status + ' | ' +
+ '' + req.Latency + ' | ' +
+ '' + formatBytes(req.BytesSent) + ' | ' +
+ '' + req.ClientIP + ' | ' +
+ '
'
+ ).join('');
+ document.querySelector('#recentRequests tbody').innerHTML = recentRequestsHtml;
+
+ document.getElementById('lastUpdate').textContent = '最后更新: ' + new Date().toLocaleTimeString();
+ }
+
function refreshMetrics() {
fetch('/metrics', {
headers: {
@@ -377,19 +523,6 @@ var metricsTemplate = `
.catch(error => console.error('Error:', error));
}
- function updateMetrics(data) {
- document.getElementById('uptime').textContent = data.uptime;
- document.getElementById('activeRequests').textContent = data.active_requests;
- document.getElementById('totalRequests').textContent = data.total_requests;
- document.getElementById('totalErrors').textContent = data.total_errors;
- document.getElementById('errorRate').textContent = (data.error_rate * 100).toFixed(2) + '%';
- document.getElementById('numGoroutine').textContent = data.num_goroutine;
- document.getElementById('memoryUsage').textContent = data.memory_usage;
- document.getElementById('avgResponseTime').textContent = data.avg_response_time;
- document.getElementById('requestsPerSecond').textContent = data.requests_per_second.toFixed(2);
- document.getElementById('lastUpdate').textContent = '最后更新: ' + new Date().toLocaleTimeString();
- }
-
// 初始加载
refreshMetrics();