package middleware import ( "errors" "fmt" "net/http" "strings" "time" "github.com/gin-gonic/gin" "github.com/go-logr/logr" "edge-infra.dev/pkg/lib/fog" ) // TODO: should make use of fog.MiddlewareLogger once it is able to log.WithValues the request properly (see pkg/edge/api/middleware/request.go) func RequestLogger(log logr.Logger) gin.HandlerFunc { return func(c *gin.Context) { if !shouldHandle(c) { c.Next() return } // log the request opID := fog.OperationID(c.Request.Context()) reqMsg := fmt.Sprintf("[%s] - [req]: %s %s", opID[:8], c.Request.Method, c.Request.URL.String()) reqLog := log.WithValues(fog.OperationFields(opID)...) reqLog.Info(reqMsg) t := time.Now() c.Next() resLog := log.WithValues(fog.OperationFields(opID)...) // log the response status := c.Writer.Status() logmsg := fmt.Sprintf("[%s] - [res]: %s %s %d (%s)", opID[:8], c.Request.Method, c.Request.URL.Path, status, http.StatusText(status)) fields := map[string]interface{}{ "requestMethod": c.Request.Method, "requestUrl": c.Request.URL.String(), "remoteIp": c.Request.RemoteAddr, "referer": c.Request.Referer(), "latency": time.Since(t).String(), "status": status, "userAgent": c.Request.UserAgent(), "responseSize": c.Writer.Size(), } if status < 500 { resLog.Info(logmsg, "httpRequest", fields) } else { resLog.Error(errors.New(http.StatusText(status)), logmsg, "httpRequest", fields) } } } // shouldHandle returns false if we don't want to log the current request func shouldHandle(c *gin.Context) bool { if c.FullPath() == "/ready" || c.FullPath() == "/live" { return false } if c.Request.Method == http.MethodOptions { return false } if !shouldLogRequest(c.Request.URL.String()) { return false } return true } func shouldLogRequest(url string) bool { blacklist := []string{".js", ".css", ".ico", ".json", ".png"} for _, suffix := range blacklist { if strings.HasSuffix(url, suffix) { return false } } urls := []string{"/.well-known/", "/static/", "/metrics"} for _, item := range urls { if strings.Contains(url, item) { return false } } return true }