package webutils import ( "net/http" "strings" "time" "github.com/rs/zerolog" "github.com/rs/zerolog/hlog" "github.com/rs/zerolog/log" ) func BuildLoggingMiddleware( status500IsError bool, ignorePaths []string, extras map[string]string, ) HandlerBuilder { return func(h http.Handler) http.Handler { return ChainMiddlewares(h, hlog.NewHandler(log.Logger), hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) { for _, p := range ignorePaths { if strings.HasPrefix(r.URL.Path, p) { return } } var logger *zerolog.Event if status >= 500 { if status500IsError { logger = hlog.FromRequest(r).Error() } else { logger = hlog.FromRequest(r).Warn() } } else { logger = hlog.FromRequest(r).Info() } logger = logger. Str("method", r.Method). Stringer("url", r.URL). Int("status", status). Int("size", size). Dur("duration", duration) for k, v := range extras { logger = logger.Str(k, v) } logger.Send() }), RealIpAppenderMiddleware("ip"), hlog.UserAgentHandler("user_agent"), hlog.RefererHandler("referer"), hlog.RequestIDHandler("req_id", "Request-Id"), ) } } func LoggingMiddleware(handler http.Handler) http.Handler { return ChainMiddlewares(handler, hlog.NewHandler(log.Logger), hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) { if strings.HasPrefix(r.URL.Path, "/assets") { return } hlog.FromRequest(r).Info(). Str("method", r.Method). Stringer("url", r.URL). Int("status", status). Int("size", size). Dur("duration", duration). Send() }), RealIpAppenderMiddleware("ip"), hlog.UserAgentHandler("user_agent"), hlog.RefererHandler("referer"), hlog.RequestIDHandler("req_id", "Request-Id"), ) } // hlog.RemoteAddrHandler except fixed to check the X-Real-Ip and X-Forwarded-For // headers first for the IP instead of relying on RemoteAddr // (which would only return the last proxy's address instead of the caller's) func RealIpAppenderMiddleware(fieldKey string) func(handler http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { IPAddress := r.Header.Get("X-Real-Ip") if IPAddress == "" { IPAddress = r.Header.Get("X-Forwarded-For") } if IPAddress == "" { IPAddress = r.RemoteAddr } if IPAddress != "" { log := zerolog.Ctx(r.Context()) log.UpdateContext(func(c zerolog.Context) zerolog.Context { return c.Str(fieldKey, IPAddress) }) } next.ServeHTTP(w, r) }) } }