Files
boc/aamos-admin-upgrade/backend/middleware/logging.go
T
Bernt 6de2455917 v1.2.0: Add Global Markets footer, translated to 9 languages
- Added GLOBAL_MARKETS_TITLE to all translation files
- Updated footer with 12 markets (4 active + 8 upcoming)
- Translated market section to: zh-cn, zh-tw, ja, ko, th, vi, id, ms, hi
- Built and deployed to production
- CloudFront invalidation: I3RTMXVFDJXWLG3SYX208OP1CC
2026-07-08 19:56:03 +00:00

80 lines
1.9 KiB
Go

package middleware
import (
"net/http"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/hlog"
)
// responseWriter wraps http.ResponseWriter to capture status code and bytes written.
type responseWriter struct {
http.ResponseWriter
status int
bytes int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.status = code
rw.ResponseWriter.WriteHeader(code)
}
func (rw *responseWriter) Write(b []byte) (int, error) {
n, err := rw.ResponseWriter.Write(b)
rw.bytes += n
return n, err
}
// Logger returns a zerolog structured logging middleware. It logs each request
// with method, path, status, latency, remote IP, and request ID (if set by
// hlog.RequestIDHandler upstream).
func Logger(log zerolog.Logger) 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, status: http.StatusOK}
next.ServeHTTP(rw, r)
latency := time.Since(start)
event := log.Info()
// Attach request ID if hlog placed one in context.
if id, ok := hlog.IDFromRequest(r); ok {
event = event.Str("req_id", id.String())
}
event.
Str("method", r.Method).
Str("path", r.URL.Path).
Str("query", r.URL.RawQuery).
Int("status", rw.status).
Int("bytes", rw.bytes).
Dur("latency_ms", latency).
Str("remote_ip", realIP(r)).
Str("user_agent", r.UserAgent()).
Msg("request")
})
}
}
// realIP returns the originating IP, preferring X-Forwarded-For / X-Real-IP
// headers set by a trusted reverse proxy.
func realIP(r *http.Request) string {
if ip := r.Header.Get("X-Real-IP"); ip != "" {
return ip
}
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
// X-Forwarded-For may be a comma-separated list; take the first entry.
for i := 0; i < len(ip); i++ {
if ip[i] == ',' {
return ip[:i]
}
}
return ip
}
return r.RemoteAddr
}