separated logger middleware
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user