2025-01-10 01:20:45 +08:00

76 lines
1.8 KiB
Go

package httplog
import (
"context"
"log/slog"
"net/http"
"time"
"git.jeffthecoder.xyz/guochao/cache-proxy/pkgs/middleware/handlerlog"
)
type ctxKey int
const (
loggerKey ctxKey = iota
)
type Config struct {
LogStart bool
LogStartLevel slog.Level
LogFinish bool
LogFinishLevel slog.Level
}
type responseRecorder struct {
http.ResponseWriter
StatusCode int
}
func (recorder *responseRecorder) WriteHeader(statusCode int) {
recorder.StatusCode = statusCode
recorder.ResponseWriter.WriteHeader(statusCode)
}
func Log(config Config) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
args := []any{
"remote_addr", r.RemoteAddr,
"host", r.Host,
"path", r.URL.Path,
}
if pattern, handlerFound := handlerlog.Pattern(r); handlerFound {
args = append(args, "handler", pattern)
}
startTime := time.Now()
if config.LogStart {
slog.With(append(args, "time", startTime)...).Log(r.Context(), config.LogStartLevel, "request start")
}
recorder := &responseRecorder{ResponseWriter: w, StatusCode: 200}
next.ServeHTTP(recorder, r.WithContext(context.WithValue(r.Context(), loggerKey, slog.With(args...))))
if config.LogFinish {
finishTime := time.Now()
slog.With(append(args, "time", finishTime, "duration", finishTime.Sub(startTime), "status", recorder.StatusCode)...).Log(r.Context(), config.LogFinishLevel, "request finished")
}
})
}
}
func Logger(r *http.Request) *slog.Logger {
if logger, ok := r.Context().Value(loggerKey).(*slog.Logger); ok {
return logger.With("time", time.Now())
}
return slog.With(
"remote_addr", r.RemoteAddr,
"host", r.Host,
"path", r.URL.Path,
"time", time.Now(),
)
}