初始化
This commit is contained in:
167
server/middleware/traffic.go
Normal file
167
server/middleware/traffic.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// TrafficStats 全局流量统计
|
||||
var TrafficStats = &trafficStats{
|
||||
startTime: time.Now(),
|
||||
}
|
||||
|
||||
type trafficStats struct {
|
||||
startTime time.Time
|
||||
totalRequests int64
|
||||
totalBytesIn int64
|
||||
totalBytesOut int64
|
||||
activeConns int64
|
||||
|
||||
// 按状态码统计
|
||||
status2xx int64
|
||||
status3xx int64
|
||||
status4xx int64
|
||||
status5xx int64
|
||||
|
||||
// 最近请求记录(滑动窗口)
|
||||
recentRequests []requestRecord
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type requestRecord struct {
|
||||
Timestamp time.Time
|
||||
IP string
|
||||
Path string
|
||||
Status int
|
||||
Bytes int
|
||||
}
|
||||
|
||||
// TrafficInfo 流量信息
|
||||
type TrafficInfo struct {
|
||||
Uptime string `json:"uptime"`
|
||||
TotalRequests int64 `json:"total_requests"`
|
||||
TotalBytesIn int64 `json:"total_bytes_in"`
|
||||
TotalBytesOut int64 `json:"total_bytes_out"`
|
||||
ActiveConns int64 `json:"active_conns"`
|
||||
QPS float64 `json:"qps"` // 每秒请求数
|
||||
Status2xx int64 `json:"status_2xx"`
|
||||
Status3xx int64 `json:"status_3xx"`
|
||||
Status4xx int64 `json:"status_4xx"`
|
||||
Status5xx int64 `json:"status_5xx"`
|
||||
}
|
||||
|
||||
// GetTrafficInfo 获取流量统计信息
|
||||
func GetTrafficInfo() TrafficInfo {
|
||||
uptime := time.Since(TrafficStats.startTime).Truncate(time.Second)
|
||||
|
||||
// 计算QPS(最近60秒)
|
||||
TrafficStats.mu.Lock()
|
||||
cutoff := time.Now().Add(-60 * time.Second)
|
||||
recent := 0
|
||||
for _, r := range TrafficStats.recentRequests {
|
||||
if r.Timestamp.After(cutoff) {
|
||||
recent++
|
||||
}
|
||||
}
|
||||
TrafficStats.mu.Unlock()
|
||||
|
||||
var qps float64
|
||||
if uptime.Seconds() > 0 {
|
||||
qps = float64(recent) / 60.0
|
||||
}
|
||||
|
||||
return TrafficInfo{
|
||||
Uptime: uptime.String(),
|
||||
TotalRequests: atomic.LoadInt64(&TrafficStats.totalRequests),
|
||||
TotalBytesIn: atomic.LoadInt64(&TrafficStats.totalBytesIn),
|
||||
TotalBytesOut: atomic.LoadInt64(&TrafficStats.totalBytesOut),
|
||||
ActiveConns: atomic.LoadInt64(&TrafficStats.activeConns),
|
||||
QPS: qps,
|
||||
Status2xx: atomic.LoadInt64(&TrafficStats.status2xx),
|
||||
Status3xx: atomic.LoadInt64(&TrafficStats.status3xx),
|
||||
Status4xx: atomic.LoadInt64(&TrafficStats.status4xx),
|
||||
Status5xx: atomic.LoadInt64(&TrafficStats.status5xx),
|
||||
}
|
||||
}
|
||||
|
||||
// TrafficMonitor 流量监控中间件
|
||||
func TrafficMonitor() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
|
||||
// 增加活跃连接数
|
||||
atomic.AddInt64(&TrafficStats.activeConns, 1)
|
||||
defer atomic.AddInt64(&TrafficStats.activeConns, -1)
|
||||
|
||||
// 统计请求大小
|
||||
bytesIn := int64(c.Request.ContentLength)
|
||||
if bytesIn < 0 {
|
||||
bytesIn = 0
|
||||
}
|
||||
atomic.AddInt64(&TrafficStats.totalBytesIn, bytesIn)
|
||||
atomic.AddInt64(&TrafficStats.totalRequests, 1)
|
||||
|
||||
c.Next()
|
||||
|
||||
// 统计响应
|
||||
status := c.Writer.Status()
|
||||
bytesOut := int64(c.Writer.Size())
|
||||
|
||||
switch {
|
||||
case status >= 200 && status < 300:
|
||||
atomic.AddInt64(&TrafficStats.status2xx, 1)
|
||||
case status >= 300 && status < 400:
|
||||
atomic.AddInt64(&TrafficStats.status3xx, 1)
|
||||
case status >= 400 && status < 500:
|
||||
atomic.AddInt64(&TrafficStats.status4xx, 1)
|
||||
case status >= 500:
|
||||
atomic.AddInt64(&TrafficStats.status5xx, 1)
|
||||
}
|
||||
|
||||
// 记录最近请求
|
||||
TrafficStats.mu.Lock()
|
||||
TrafficStats.recentRequests = append(TrafficStats.recentRequests, requestRecord{
|
||||
Timestamp: start,
|
||||
IP: c.ClientIP(),
|
||||
Path: c.Request.URL.Path,
|
||||
Status: status,
|
||||
Bytes: int(bytesOut),
|
||||
})
|
||||
// 只保留最近5分钟的记录
|
||||
cutoff := time.Now().Add(-5 * time.Minute)
|
||||
valid := TrafficStats.recentRequests[:0]
|
||||
for _, r := range TrafficStats.recentRequests {
|
||||
if r.Timestamp.After(cutoff) {
|
||||
valid = append(valid, r)
|
||||
}
|
||||
}
|
||||
TrafficStats.recentRequests = valid
|
||||
TrafficStats.mu.Unlock()
|
||||
|
||||
// 慢请求日志
|
||||
duration := time.Since(start)
|
||||
if duration > 5*time.Second {
|
||||
log.Printf("[SLOW] %s %s %d %v", c.ClientIP(), c.Request.URL.Path, status, duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetRecentRequests 获取最近的请求记录
|
||||
func GetRecentRequests(limit int) []requestRecord {
|
||||
TrafficStats.mu.Lock()
|
||||
defer TrafficStats.mu.Unlock()
|
||||
|
||||
total := len(TrafficStats.recentRequests)
|
||||
if limit <= 0 || limit > total {
|
||||
limit = total
|
||||
}
|
||||
|
||||
start := total - limit
|
||||
result := make([]requestRecord, limit)
|
||||
copy(result, TrafficStats.recentRequests[start:])
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user