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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var avgLatency int64
|
// 添加安全的类型转换函数
|
||||||
if latency, ok := stats["avg_latency"]; ok && latency != nil {
|
safeInt64 := func(v interface{}) int64 {
|
||||||
avgLatency = latency.(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{
|
metrics := Metrics{
|
||||||
Uptime: uptime.String(),
|
Uptime: uptime.String(),
|
||||||
ActiveRequests: stats["active_requests"].(int64),
|
ActiveRequests: safeInt64(stats["active_requests"]),
|
||||||
TotalRequests: stats["total_requests"].(int64),
|
TotalRequests: totalRequests,
|
||||||
TotalErrors: stats["total_errors"].(int64),
|
TotalErrors: safeInt64(stats["total_errors"]),
|
||||||
ErrorRate: float64(stats["total_errors"].(int64)) / float64(stats["total_requests"].(int64)),
|
ErrorRate: float64(safeInt64(stats["total_errors"])) / float64(max(totalRequests, 1)),
|
||||||
NumGoroutine: stats["num_goroutine"].(int),
|
NumGoroutine: safeInt(stats["num_goroutine"]),
|
||||||
MemoryUsage: stats["memory_usage"].(string),
|
MemoryUsage: stats["memory_usage"].(string),
|
||||||
AverageResponseTime: metrics.FormatDuration(time.Duration(avgLatency)),
|
AverageResponseTime: metrics.FormatDuration(time.Duration(safeInt64(stats["avg_latency"]))),
|
||||||
TotalBytes: stats["total_bytes"].(int64),
|
TotalBytes: safeInt64(stats["total_bytes"]),
|
||||||
BytesPerSecond: float64(stats["total_bytes"].(int64)) / metrics.Max(uptime.Seconds(), 1),
|
BytesPerSecond: float64(safeInt64(stats["total_bytes"])) / metrics.Max(uptime.Seconds(), 1),
|
||||||
RequestsPerSecond: float64(stats["total_requests"].(int64)) / metrics.Max(uptime.Seconds(), 1),
|
RequestsPerSecond: float64(totalRequests) / metrics.Max(uptime.Seconds(), 1),
|
||||||
StatusCodeStats: stats["status_code_stats"].(map[string]int64),
|
StatusCodeStats: stats["status_code_stats"].(map[string]int64),
|
||||||
TopPaths: stats["top_paths"].([]models.PathMetrics),
|
TopPaths: stats["top_paths"].([]models.PathMetrics),
|
||||||
RecentRequests: stats["recent_requests"].([]models.RequestLog),
|
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 = `
|
var loginTemplate = `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"proxy-go/internal/config"
|
"proxy-go/internal/config"
|
||||||
"proxy-go/internal/metrics"
|
"proxy-go/internal/metrics"
|
||||||
"proxy-go/internal/utils"
|
"proxy-go/internal/utils"
|
||||||
@ -22,7 +23,8 @@ const (
|
|||||||
|
|
||||||
var bufferPool = sync.Pool{
|
var bufferPool = sync.Pool{
|
||||||
New: func() interface{} {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确定基础URL
|
// 确定标基础URL
|
||||||
targetBase := utils.GetTargetURL(h.client, r, pathConfig, decodedPath)
|
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, "/")
|
parts := strings.Split(decodedPath, "/")
|
||||||
@ -223,8 +234,10 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// 大响应使用流式传输
|
// 大响应使用流式传输
|
||||||
var bytesCopied int64
|
var bytesCopied int64
|
||||||
if f, ok := w.(http.Flusher); ok {
|
if f, ok := w.(http.Flusher); ok {
|
||||||
buf := bufferPool.Get().([]byte)
|
bufPtr := bufferPool.Get().(*[]byte)
|
||||||
defer bufferPool.Put(buf)
|
defer bufferPool.Put(bufPtr)
|
||||||
|
buf := *bufPtr
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, rerr := resp.Body.Read(buf)
|
n, rerr := resp.Body.Read(buf)
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user