wood chen 83e0226e41 feat(monitoring, public): enhance metrics logging and display
- Added a new function to format latency metrics in both Go and JavaScript for improved readability.
- Updated the LogRequest function to parse and store only the domain of the referer, enhancing data clarity.
- Modified the recent requests and top referers display logic in the HTML to improve performance and maintainability.
- Ensured that the recent requests are displayed in a more user-friendly format, including formatted latency values.
2024-12-01 00:03:26 +08:00

135 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package monitoring
import (
"fmt"
"net/url"
"runtime"
"strings"
"sync"
"time"
)
type SystemMetrics struct {
// 基础指标
Uptime time.Duration `json:"uptime"`
StartTime time.Time `json:"start_time"`
// 系统指标
NumCPU int `json:"num_cpu"`
NumGoroutine int `json:"num_goroutine"`
MemoryStats struct {
Alloc uint64 `json:"alloc"`
TotalAlloc uint64 `json:"total_alloc"`
Sys uint64 `json:"sys"`
HeapAlloc uint64 `json:"heap_alloc"`
HeapSys uint64 `json:"heap_sys"`
} `json:"memory_stats"`
// 性能指标
RequestCount int64 `json:"request_count"`
AverageLatency float64 `json:"average_latency"`
// 流量统计
TotalBytesIn int64 `json:"total_bytes_in"`
TotalBytesOut int64 `json:"total_bytes_out"`
// 状态码统计
StatusCodes map[int]int64 `json:"status_codes"`
// 路径延迟统计
PathLatencies map[string]float64 `json:"path_latencies"`
// 最近请求
RecentRequests []RequestLog `json:"recent_requests"`
// 热门引用来源
TopReferers map[string]int64 `json:"top_referers"`
}
type RequestLog struct {
Time time.Time `json:"time"`
Path string `json:"path"`
Method string `json:"method"`
StatusCode int `json:"status_code"`
Latency float64 `json:"latency"`
IP string `json:"ip"`
Referer string `json:"referer"`
}
var (
metrics SystemMetrics
mu sync.RWMutex
startTime = time.Now()
)
func init() {
metrics.StatusCodes = make(map[int]int64)
metrics.PathLatencies = make(map[string]float64)
metrics.TopReferers = make(map[string]int64)
metrics.RecentRequests = make([]RequestLog, 0, 100)
}
func CollectMetrics() *SystemMetrics {
mu.Lock()
defer mu.Unlock()
var m runtime.MemStats
runtime.ReadMemStats(&m)
metrics.Uptime = time.Since(startTime)
metrics.StartTime = startTime
metrics.NumCPU = runtime.NumCPU()
metrics.NumGoroutine = runtime.NumGoroutine()
metrics.MemoryStats.Alloc = m.Alloc
metrics.MemoryStats.TotalAlloc = m.TotalAlloc
metrics.MemoryStats.Sys = m.Sys
metrics.MemoryStats.HeapAlloc = m.HeapAlloc
metrics.MemoryStats.HeapSys = m.HeapSys
return &metrics
}
func formatLatency(microseconds float64) string {
if microseconds < 1000 {
return fmt.Sprintf("%.2fµs", microseconds)
}
if microseconds < 1000000 {
return fmt.Sprintf("%.2fms", microseconds/1000)
}
return fmt.Sprintf("%.2fs", microseconds/1000000)
}
func LogRequest(log RequestLog) {
mu.Lock()
defer mu.Unlock()
metrics.RequestCount++
metrics.StatusCodes[log.StatusCode]++
// 处理 referer只保留域名
if log.Referer != "direct" {
if parsedURL, err := url.Parse(log.Referer); err == nil {
metrics.TopReferers[parsedURL.Host]++
}
} else {
metrics.TopReferers["direct"]++
}
// 只记录 API 请求
if strings.HasPrefix(log.Path, "/pic/") || strings.HasPrefix(log.Path, "/video/") {
// 更新路径延迟
if existing, ok := metrics.PathLatencies[log.Path]; ok {
metrics.PathLatencies[log.Path] = (existing + log.Latency) / 2
} else {
metrics.PathLatencies[log.Path] = log.Latency
}
// 保存最近请求记录,插入到开头
metrics.RecentRequests = append([]RequestLog{log}, metrics.RecentRequests...)
if len(metrics.RecentRequests) > 100 {
metrics.RecentRequests = metrics.RecentRequests[:100]
}
}
}