From 85ccace24fc4f3f56be03faf4cf6eca863e5b402 Mon Sep 17 00:00:00 2001 From: Angel Beltran Date: Sun, 11 Jan 2026 17:05:20 -0700 Subject: [PATCH] separated logger middleware --- internal/server/middleware/log.go | 81 +++++++++++++++++++++++++++++ internal/server/response/handler.go | 6 ++- internal/server/response/mux.go | 34 ------------ internal/server/router/mux.go | 36 +++++++++++++ internal/server/server.go | 51 +----------------- 5 files changed, 124 insertions(+), 84 deletions(-) create mode 100644 internal/server/middleware/log.go delete mode 100644 internal/server/response/mux.go create mode 100644 internal/server/router/mux.go diff --git a/internal/server/middleware/log.go b/internal/server/middleware/log.go new file mode 100644 index 0000000..87d2637 --- /dev/null +++ b/internal/server/middleware/log.go @@ -0,0 +1,81 @@ +package middleware + +import ( + "context" + "log/slog" + "net/http" + "time" + + "ruben/inventory2/internal/server/response" +) + +func LogRequests(ctx context.Context, logger *slog.Logger) response.Middleware { + reqIDCh := newRequestIDProvider(ctx) + + return func(fn response.HandlerFunc) response.HandlerFunc { + return func(r *http.Request) (response.Response, error) { + start := time.Now() + + args := []any{ + "id", <-reqIDCh, + "url", r.URL, + } + + logger.Debug("Request", args...) + + res, err := fn(r) + end := time.Now() + + var status int + if err != nil { + status = response.GetStatusFromError(err) + } else { + var ok bool + if status, ok = res.GetStatus(); !ok { + status = http.StatusOK + } + } + + args = append(args, + "status", status, + "elapsed", time.Duration(end.UnixNano()-start.UnixNano()), + ) + + switch status / 100 { + case 1: + logger.Debug("Response", args...) + case 2: + logger.Debug("Response", args...) + case 3: + logger.Debug("Response", args...) + case 4: + logger.Warn("Response", args...) + default: + logger.Error("Response", args...) + } + + return res, err + } + } +} + +func newRequestIDProvider(ctx context.Context) <-chan int { + reqIDCh := make(chan int) + + go func() { + defer close(reqIDCh) + + nextReqID := 1 + + for { + select { + case reqIDCh <- nextReqID: + nextReqID += 1 + case <-ctx.Done(): + return + } + } + }() + + return reqIDCh +} diff --git a/internal/server/response/handler.go b/internal/server/response/handler.go index 4d7674c..ea0d0a6 100644 --- a/internal/server/response/handler.go +++ b/internal/server/response/handler.go @@ -4,7 +4,11 @@ import ( "net/http" ) -type HandlerFunc = func(r *http.Request) (Response, error) +type ( + HandlerFunc = func(r *http.Request) (Response, error) + + Middleware = func(HandlerFunc) HandlerFunc +) func Handler(f HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { diff --git a/internal/server/response/mux.go b/internal/server/response/mux.go deleted file mode 100644 index f704812..0000000 --- a/internal/server/response/mux.go +++ /dev/null @@ -1,34 +0,0 @@ -package response - -import "net/http" - -type ( - Mux struct { - Mux *http.ServeMux - middleware []Middleware - } - - Middleware = func(HandlerFunc) HandlerFunc -) - -func NewMux(ms ...Middleware) *Mux { - return &Mux{ - Mux: http.NewServeMux(), - middleware: ms, - } -} - -func (m *Mux) Handle(pattern string, fn HandlerFunc) { - for _, mw := range m.middleware { - prev := fn - fn = mw(func(r *http.Request) (Response, error) { - return prev(r) - }) - } - - m.Mux.Handle(pattern, Handler(fn)) -} - -func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { - m.Mux.ServeHTTP(w, r) -} diff --git a/internal/server/router/mux.go b/internal/server/router/mux.go new file mode 100644 index 0000000..e8a4569 --- /dev/null +++ b/internal/server/router/mux.go @@ -0,0 +1,36 @@ +package router + +import ( + "net/http" + + "ruben/inventory2/internal/server/response" +) + +type ( + Mux struct { + Mux *http.ServeMux + middleware []response.Middleware + } +) + +func NewMux(ms ...response.Middleware) *Mux { + return &Mux{ + Mux: http.NewServeMux(), + middleware: ms, + } +} + +func (m *Mux) Handle(pattern string, fn response.HandlerFunc) { + for _, mw := range m.middleware { + prev := fn + fn = mw(func(r *http.Request) (response.Response, error) { + return prev(r) + }) + } + + m.Mux.Handle(pattern, response.Handler(fn)) +} + +func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { + m.Mux.ServeHTTP(w, r) +} diff --git a/internal/server/server.go b/internal/server/server.go index ab1595d..33e7bc0 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -10,7 +10,6 @@ import ( "path" "strconv" "strings" - "time" "github.com/angelbeltran/templater" @@ -21,6 +20,7 @@ import ( "ruben/inventory2/internal/domains/raw_events" "ruben/inventory2/internal/server/middleware" "ruben/inventory2/internal/server/response" + "ruben/inventory2/internal/server/router" "ruben/inventory2/internal/server/webhooks" etsy_webhooks "ruben/inventory2/internal/server/webhooks/etsy" ) @@ -46,54 +46,7 @@ func NewServer( etsy *etsy_platform.Platform, auth *authentication.Authenticator, ) *Server { - reqIDCh := newRequestIDProvider(ctx) - - reqLog := logger.WithGroup("request") - mux := response.NewMux(func(fn response.HandlerFunc) response.HandlerFunc { - return func(r *http.Request) (response.Response, error) { - start := time.Now() - - args := []any{ - "id", <-reqIDCh, - "url", r.URL, - } - - reqLog.Debug("Request", args...) - - res, err := fn(r) - end := time.Now() - - var status int - if err != nil { - status = response.GetStatusFromError(err) - } else { - var ok bool - if status, ok = res.GetStatus(); !ok { - status = http.StatusOK - } - } - - args = append(args, - "status", status, - "elapsed", time.Duration(end.UnixNano()-start.UnixNano()), - ) - - switch status / 100 { - case 1: - reqLog.Debug("Response", args...) - case 2: - reqLog.Debug("Response", args...) - case 3: - reqLog.Debug("Response", args...) - case 4: - reqLog.Warn("Response", args...) - default: - reqLog.Error("Response", args...) - } - - return res, err - } - }) + mux := router.NewMux(middleware.LogRequests(ctx, logger.WithGroup("request"))) s := &Server{ log: logger,