- Reorder HandleGameEvents to create NATS subscriptions before SSE - Use chi's middleware.NewWrapResponseWriter for proper http.Flusher support - Add slog-zerolog adapter for unified logging - Add ErrorLog to HTTP server for better error visibility - Change session Cookie.Secure to false for HTTP support - Change heartbeat from 15s to 10s - Remove ConnectionIndicator patching (was causing PatchElementsNoTargetsFound) The key fix was using chi's response writer wrapper which properly implements http.Flusher, allowing SSE data to be flushed immediately instead of being buffered.
118 lines
2.4 KiB
Go
118 lines
2.4 KiB
Go
package logging
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"github.com/ryanhamamura/games/config"
|
|
)
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
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()
|
|
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
|
|
|
|
next.ServeHTTP(ww, r)
|
|
|
|
status := ww.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")
|
|
}
|
|
})
|
|
}
|
|
}
|