Log returns a middleware that logs requests. If logger is nil, the logger will be extracted from the context.
(logger log.Interface, ignorePathsArray []string)
| 32 | // Log returns a middleware that logs requests. |
| 33 | // If logger is nil, the logger will be extracted from the context. |
| 34 | func Log(logger log.Interface, ignorePathsArray []string) MiddlewareFunc { |
| 35 | ignorePaths := make(map[string]struct{}) |
| 36 | for _, path := range ignorePathsArray { |
| 37 | ignorePaths[path] = struct{}{} |
| 38 | } |
| 39 | return func(next http.Handler) http.Handler { |
| 40 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 41 | logFields := log.Fields( |
| 42 | "http.method", r.Method, |
| 43 | "http.path", r.URL.Path, |
| 44 | "peer.address", r.RemoteAddr, |
| 45 | "request_id", r.Header.Get(requestIDHeader), |
| 46 | ) |
| 47 | if xRealIP := r.Header.Get("X-Real-Ip"); xRealIP != "" { |
| 48 | logFields = logFields.WithField("peer.real_ip", xRealIP) |
| 49 | } |
| 50 | |
| 51 | ctx, getError := webhandlers.NewContextWithErrorValue(r.Context()) |
| 52 | requestLogger := logger |
| 53 | if requestLogger == nil { |
| 54 | requestLogger = log.FromContext(ctx) |
| 55 | } |
| 56 | requestLogger = requestLogger.WithFields(logFields) |
| 57 | |
| 58 | r = r.WithContext(log.NewContext(ctx, requestLogger)) |
| 59 | metrics := httpsnoop.CaptureMetrics(next, w, r) |
| 60 | |
| 61 | if metrics.Code < 400 { |
| 62 | if _, ignore := ignorePaths[r.URL.Path]; ignore { |
| 63 | return |
| 64 | } |
| 65 | } |
| 66 | if shouldSuppressError(metrics.Code) { |
| 67 | return |
| 68 | } |
| 69 | |
| 70 | logFields = logFields.With(map[string]any{ |
| 71 | "http.status": metrics.Code, |
| 72 | "duration": metrics.Duration.Round(time.Microsecond * 100), |
| 73 | }) |
| 74 | if authorization := r.Header.Get("Authorization"); authorization != "" { |
| 75 | parts := strings.SplitN(authorization, " ", 2) |
| 76 | if len(parts) == 2 && strings.ToLower(parts[0]) == "bearer" { |
| 77 | if tokenType, tokenID, _, err := auth.SplitToken(parts[1]); err == nil { |
| 78 | logFields = logFields.WithFields(log.Fields( |
| 79 | "auth.token_type", tokenType.String(), |
| 80 | "auth.token_id", tokenID, |
| 81 | )) |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 | if err := getError(); err != nil { |
| 86 | logFields = logFields.WithError(err) |
| 87 | } |
| 88 | requestLogger = requestLogger.WithFields(logFields) |
| 89 | |
| 90 | switch { |
| 91 | case metrics.Code == http.StatusNotImplemented: |