package logging import ( "fmt" "net/http" "time" "github.com/ryanhamamura/games/config" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) const ( ansiReset = "\033[0m" ansiBrightRed = "\033[31;1m" ansiBrightGreen = "\033[32;1m" ansiBrightYellow = "\033[33;1m" ansiBrightMagenta = "\033[35;1m" ansiBrightCyan = "\033[36;1m" ansiGreen = "\033[32m" ansiYellow = "\033[33m" ansiRed = "\033[31m" ) func colorStatus(status int, useColor bool) string { s := fmt.Sprintf("%d", status) if !useColor { return s } switch { case status < 200: return ansiBrightGreen + s + ansiReset case status < 300: return ansiBrightGreen + s + ansiReset case status < 400: return ansiBrightCyan + s + ansiReset case status < 500: return ansiBrightYellow + s + ansiReset default: return ansiBrightRed + s + ansiReset } } func colorMethod(method string, useColor bool) string { if !useColor { return method } return ansiBrightMagenta + method + ansiReset } func colorLatency(d time.Duration, useColor bool) string { s := d.String() if !useColor { return s } switch { case d < 500*time.Millisecond: return ansiGreen + s + ansiReset case d < 5*time.Second: return ansiYellow + s + ansiReset default: return ansiRed + s + ansiReset } } type responseWriter struct { http.ResponseWriter status int } func (rw *responseWriter) WriteHeader(code int) { rw.status = code rw.ResponseWriter.WriteHeader(code) } func RequestLogger(logger *zerolog.Logger, env config.Environment) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() rw := &responseWriter{ResponseWriter: w} next.ServeHTTP(rw, r) status := rw.status if status == 0 { status = http.StatusOK } l := log.Ctx(r.Context()) if l.GetLevel() == zerolog.Disabled { l = logger } var evt *zerolog.Event switch { case status < 400: evt = l.Info() case status < 500: evt = l.Warn() case status < 600: evt = l.Error() default: evt = l.Info() } latency := time.Since(start) switch env { case config.Dev: useColor := true evt.Msg(fmt.Sprintf("%s %s %s [%s]", colorStatus(status, useColor), colorMethod(r.Method, useColor), r.URL.Path, colorLatency(latency, useColor), )) default: evt. Int("status", status). Str("method", r.Method). Str("path", r.URL.Path). Dur("latency", latency). Msg("request") } }) } }