93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
package observability
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"wx_service/internal/middleware"
|
|
)
|
|
|
|
var requestSeq uint64
|
|
|
|
func RequestLogMiddleware(metrics *Collector) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
startedAt := time.Now()
|
|
|
|
requestID := strings.TrimSpace(c.GetHeader("X-Request-ID"))
|
|
if requestID == "" {
|
|
seq := atomic.AddUint64(&requestSeq, 1)
|
|
requestID = fmt.Sprintf("req-%d-%d", time.Now().UnixNano(), seq)
|
|
}
|
|
c.Writer.Header().Set("X-Request-ID", requestID)
|
|
|
|
c.Next()
|
|
|
|
status := c.Writer.Status()
|
|
latency := time.Since(startedAt)
|
|
if metrics != nil {
|
|
metrics.Observe(status, latency)
|
|
}
|
|
|
|
path := c.FullPath()
|
|
if path == "" {
|
|
path = c.Request.URL.Path
|
|
}
|
|
|
|
level := "info"
|
|
if status >= 500 {
|
|
level = "error"
|
|
} else if status >= 400 {
|
|
level = "warn"
|
|
}
|
|
|
|
entry := map[string]any{
|
|
"ts": time.Now().UTC().Format(time.RFC3339),
|
|
"level": level,
|
|
"request_id": requestID,
|
|
"method": c.Request.Method,
|
|
"path": path,
|
|
"status": status,
|
|
"latency_ms": float64(latency.Microseconds()) / 1000.0,
|
|
"client_ip": c.ClientIP(),
|
|
}
|
|
|
|
if user, ok := middleware.CurrentUser(c); ok && user != nil {
|
|
entry["uid"] = user.ID
|
|
}
|
|
if len(c.Errors) > 0 {
|
|
entry["errors"] = c.Errors.String()
|
|
}
|
|
|
|
payload, err := json.Marshal(entry)
|
|
if err != nil {
|
|
log.Printf("observability marshal log failed: %v", err)
|
|
return
|
|
}
|
|
log.Println(string(payload))
|
|
}
|
|
}
|
|
|
|
func BasicMetricsHandler(metrics *Collector) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
if metrics == nil {
|
|
c.JSON(http.StatusServiceUnavailable, gin.H{
|
|
"code": http.StatusServiceUnavailable,
|
|
"message": "metrics not initialized",
|
|
})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": http.StatusOK,
|
|
"message": "success",
|
|
"data": metrics.Snapshot(),
|
|
})
|
|
}
|
|
}
|