mirror of
https://github.com/woodchen-ink/proxy-go.git
synced 2025-07-18 08:31:55 +08:00
feat(metrics): improve metrics handling with safe type conversions and enhanced request statistics
- Introduced safe type conversion functions to prevent panics when accessing metrics data. - Updated MetricsHandler to utilize these functions for retrieving active requests, total requests, total errors, and average response time. - Enhanced error rate calculation to avoid division by zero. - Refactored buffer pool management in ProxyHandler for better memory handling. - Improved target URL determination logic based on file extensions for more flexible proxy behavior.
This commit is contained in:
parent
1db0e6ae98
commit
9602034f9d
@ -47,23 +47,40 @@ func (h *ProxyHandler) MetricsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var avgLatency int64
|
||||
if latency, ok := stats["avg_latency"]; ok && latency != nil {
|
||||
avgLatency = latency.(int64)
|
||||
// 添加安全的类型转换函数
|
||||
safeInt64 := func(v interface{}) int64 {
|
||||
if v == nil {
|
||||
return 0
|
||||
}
|
||||
if i, ok := v.(int64); ok {
|
||||
return i
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
safeInt := func(v interface{}) int {
|
||||
if v == nil {
|
||||
return 0
|
||||
}
|
||||
if i, ok := v.(int); ok {
|
||||
return i
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
totalRequests := safeInt64(stats["total_requests"])
|
||||
metrics := Metrics{
|
||||
Uptime: uptime.String(),
|
||||
ActiveRequests: stats["active_requests"].(int64),
|
||||
TotalRequests: stats["total_requests"].(int64),
|
||||
TotalErrors: stats["total_errors"].(int64),
|
||||
ErrorRate: float64(stats["total_errors"].(int64)) / float64(stats["total_requests"].(int64)),
|
||||
NumGoroutine: stats["num_goroutine"].(int),
|
||||
ActiveRequests: safeInt64(stats["active_requests"]),
|
||||
TotalRequests: totalRequests,
|
||||
TotalErrors: safeInt64(stats["total_errors"]),
|
||||
ErrorRate: float64(safeInt64(stats["total_errors"])) / float64(max(totalRequests, 1)),
|
||||
NumGoroutine: safeInt(stats["num_goroutine"]),
|
||||
MemoryUsage: stats["memory_usage"].(string),
|
||||
AverageResponseTime: metrics.FormatDuration(time.Duration(avgLatency)),
|
||||
TotalBytes: stats["total_bytes"].(int64),
|
||||
BytesPerSecond: float64(stats["total_bytes"].(int64)) / metrics.Max(uptime.Seconds(), 1),
|
||||
RequestsPerSecond: float64(stats["total_requests"].(int64)) / metrics.Max(uptime.Seconds(), 1),
|
||||
AverageResponseTime: metrics.FormatDuration(time.Duration(safeInt64(stats["avg_latency"]))),
|
||||
TotalBytes: safeInt64(stats["total_bytes"]),
|
||||
BytesPerSecond: float64(safeInt64(stats["total_bytes"])) / metrics.Max(uptime.Seconds(), 1),
|
||||
RequestsPerSecond: float64(totalRequests) / metrics.Max(uptime.Seconds(), 1),
|
||||
StatusCodeStats: stats["status_code_stats"].(map[string]int64),
|
||||
TopPaths: stats["top_paths"].([]models.PathMetrics),
|
||||
RecentRequests: stats["recent_requests"].([]models.RequestLog),
|
||||
@ -76,6 +93,14 @@ func (h *ProxyHandler) MetricsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
func max(a, b int64) int64 {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// 修改模板,添加登录页面
|
||||
var loginTemplate = `
|
||||
<!DOCTYPE html>
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"proxy-go/internal/config"
|
||||
"proxy-go/internal/metrics"
|
||||
"proxy-go/internal/utils"
|
||||
@ -22,7 +23,8 @@ const (
|
||||
|
||||
var bufferPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, defaultBufferSize)
|
||||
buf := make([]byte, defaultBufferSize)
|
||||
return &buf
|
||||
},
|
||||
}
|
||||
|
||||
@ -108,8 +110,17 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 确定基础URL
|
||||
targetBase := utils.GetTargetURL(h.client, r, pathConfig, decodedPath)
|
||||
// 确定标基础URL
|
||||
targetBase := pathConfig.DefaultTarget
|
||||
|
||||
// 检查文件扩展名
|
||||
if pathConfig.ExtensionMap != nil {
|
||||
ext := strings.ToLower(path.Ext(decodedPath))
|
||||
if ext != "" {
|
||||
ext = ext[1:] // 移除开头的点
|
||||
targetBase = pathConfig.GetTargetForExt(ext)
|
||||
}
|
||||
}
|
||||
|
||||
// 重新编码路径,保留 '/'
|
||||
parts := strings.Split(decodedPath, "/")
|
||||
@ -223,8 +234,10 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// 大响应使用流式传输
|
||||
var bytesCopied int64
|
||||
if f, ok := w.(http.Flusher); ok {
|
||||
buf := bufferPool.Get().([]byte)
|
||||
defer bufferPool.Put(buf)
|
||||
bufPtr := bufferPool.Get().(*[]byte)
|
||||
defer bufferPool.Put(bufPtr)
|
||||
buf := *bufPtr
|
||||
|
||||
for {
|
||||
n, rerr := resp.Body.Read(buf)
|
||||
if n > 0 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user