mirror of
https://github.com/woodchen-ink/proxy-go.git
synced 2025-07-18 08:31:55 +08:00
refactor(metrics): enhance dashboard styles and optimize SQL queries
- Updated CSS styles for the metrics dashboard, improving layout with flex properties and enhanced item presentation. - Modified the status code display to use a more organized structure, allowing for better alignment and spacing. - Changed the data type for avgLatency in SaveMetrics to int64 for consistency. - Implemented a context with timeout for database queries in GetRecentMetrics, improving performance and reliability. - Optimized SQL queries to limit result sets and enhance data retrieval efficiency. These changes improve the user experience and data presentation in the metrics dashboard, providing clearer insights into performance metrics.
This commit is contained in:
parent
7cca4bab95
commit
8df86387ac
@ -396,30 +396,35 @@ var metricsTemplate = `
|
||||
|
||||
.status-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.status-labels, .status-values {
|
||||
.status-item {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
gap: 20px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
min-width: 80px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
flex: 0 0 auto;
|
||||
text-align: center;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
min-width: 60px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
flex: 0 0 auto;
|
||||
text-align: center;
|
||||
min-width: 60px;
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
}
|
||||
.loading {
|
||||
position: relative;
|
||||
@ -687,24 +692,18 @@ var metricsTemplate = `
|
||||
|
||||
// 更新状态码计
|
||||
const statusCodesHtml = '<div class="status-row">' +
|
||||
'<div class="status-labels">' +
|
||||
Object.entries(data.status_code_stats)
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(([status, _]) => {
|
||||
.map(([status, count]) => {
|
||||
const firstDigit = status.charAt(0);
|
||||
const statusClass = (firstDigit >= '2' && firstDigit <= '5')
|
||||
? 'status-' + firstDigit + 'xx'
|
||||
: 'status-other';
|
||||
return '<span class="status-badge ' + statusClass + '">' + status + '</span>';
|
||||
return '<div class="status-item">' +
|
||||
'<span class="status-badge ' + statusClass + '">' + status + '</span>' +
|
||||
'<span class="metric-value">' + count.toLocaleString() + '</span>' +
|
||||
'</div>';
|
||||
}).join('') +
|
||||
'</div>' +
|
||||
'<div class="status-values">' +
|
||||
Object.entries(data.status_code_stats)
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(([_, count]) => {
|
||||
return '<span class="metric-value">' + count.toLocaleString() + '</span>';
|
||||
}).join('') +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
const statusCodesContainer = document.getElementById('statusCodes');
|
||||
|
@ -1,6 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
@ -405,7 +406,7 @@ func (db *MetricsDB) SaveMetrics(stats map[string]interface{}) error {
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid total_bytes type")
|
||||
}
|
||||
avgLatency, ok := stats["avg_latency"].(float64)
|
||||
avgLatency, ok := stats["avg_latency"].(int64)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid avg_latency type")
|
||||
}
|
||||
@ -421,7 +422,7 @@ func (db *MetricsDB) SaveMetrics(stats map[string]interface{}) error {
|
||||
totalReqs,
|
||||
totalErrs,
|
||||
totalBytes,
|
||||
int64(avgLatency),
|
||||
avgLatency,
|
||||
errorRate,
|
||||
)
|
||||
if err != nil {
|
||||
@ -443,6 +444,10 @@ func (db *MetricsDB) GetRecentMetrics(hours float64) ([]HistoricalMetrics, error
|
||||
cacheSize int64
|
||||
}
|
||||
|
||||
// 添加查询超时
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// 处理小于1小时的情况
|
||||
if hours <= 0 {
|
||||
hours = 0.5 // 30分钟
|
||||
@ -469,8 +474,8 @@ func (db *MetricsDB) GetRecentMetrics(hours float64) ([]HistoricalMetrics, error
|
||||
timeStep = 1440 // 1天
|
||||
}
|
||||
|
||||
// 修改查询逻辑,使用 strftime 来处理时间
|
||||
rows, err := db.DB.Query(`
|
||||
// 修改查询逻辑,优化性能
|
||||
rows, err := db.DB.QueryContext(ctx, `
|
||||
WITH RECURSIVE
|
||||
time_points(ts) AS (
|
||||
SELECT strftime(?, 'now', 'localtime')
|
||||
@ -478,18 +483,20 @@ func (db *MetricsDB) GetRecentMetrics(hours float64) ([]HistoricalMetrics, error
|
||||
SELECT strftime(?, datetime(ts, '-' || ? || ' minutes'))
|
||||
FROM time_points
|
||||
WHERE ts > strftime(?, datetime('now', '-' || ? || ' hours', 'localtime'))
|
||||
LIMIT 1000
|
||||
LIMIT ? -- 限制时间点数量
|
||||
),
|
||||
grouped_metrics AS (
|
||||
SELECT
|
||||
strftime(?, timestamp) as group_time,
|
||||
MAX(total_requests) as period_requests,
|
||||
MAX(total_errors) as period_errors,
|
||||
MAX(total_bytes) as period_bytes,
|
||||
AVG(avg_latency) as avg_latency
|
||||
MAX(total_bytes) as period_bytes,
|
||||
AVG(avg_latency) as avg_latency
|
||||
FROM metrics_history
|
||||
WHERE timestamp >= datetime('now', '-' || ? || ' hours', 'localtime')
|
||||
AND timestamp < datetime('now', 'localtime') -- 添加上限
|
||||
GROUP BY group_time
|
||||
LIMIT ? -- 限制结果数量
|
||||
)
|
||||
SELECT
|
||||
tp.ts as timestamp,
|
||||
@ -500,8 +507,8 @@ func (db *MetricsDB) GetRecentMetrics(hours float64) ([]HistoricalMetrics, error
|
||||
FROM time_points tp
|
||||
LEFT JOIN grouped_metrics m ON tp.ts = m.group_time
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT 1000
|
||||
`, interval, interval, timeStep, interval, hours, interval, hours)
|
||||
LIMIT ?
|
||||
`, interval, interval, timeStep, interval, hours, 1000, interval, hours, 1000, 1000)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user