diff --git a/internal/handler/metrics.go b/internal/handler/metrics.go index 23f2f54..d3275cb 100644 --- a/internal/handler/metrics.go +++ b/internal/handler/metrics.go @@ -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 = '
' + - '
' + 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 '' + status + ''; + return '
' + + '' + status + '' + + '' + count.toLocaleString() + '' + + '
'; }).join('') + - '
' + - '
' + - Object.entries(data.status_code_stats) - .sort((a, b) => a[0].localeCompare(b[0])) - .map(([_, count]) => { - return '' + count.toLocaleString() + ''; - }).join('') + - '
' + '
'; const statusCodesContainer = document.getElementById('statusCodes'); diff --git a/internal/models/metrics.go b/internal/models/metrics.go index 12e3560..fdd6311 100644 --- a/internal/models/metrics.go +++ b/internal/models/metrics.go @@ -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 }