2021-01-18 11:46:22 +01:00
|
|
|
// Package logginghandler is a simple, zerolog based, request logging http middleware.
|
|
|
|
// It also sets `X-Request-ID` in the request and response headers.
|
2020-10-13 15:26:40 +02:00
|
|
|
package logginghandler
|
|
|
|
|
|
|
|
import (
|
2022-01-24 11:45:27 +01:00
|
|
|
"context"
|
2020-10-13 15:26:40 +02:00
|
|
|
"net/http"
|
2022-01-17 11:27:49 +01:00
|
|
|
"time"
|
2020-10-13 15:26:40 +02:00
|
|
|
|
2022-01-17 11:27:49 +01:00
|
|
|
"github.com/justinas/alice"
|
2023-02-24 10:07:06 +01:00
|
|
|
"github.com/rs/xid"
|
2020-10-13 15:26:40 +02:00
|
|
|
"github.com/rs/zerolog"
|
2022-01-14 13:48:41 +01:00
|
|
|
"github.com/rs/zerolog/hlog"
|
2022-01-24 11:45:27 +01:00
|
|
|
"github.com/rs/zerolog/log"
|
2020-10-13 15:26:40 +02:00
|
|
|
)
|
|
|
|
|
2023-02-24 10:07:06 +01:00
|
|
|
const (
|
|
|
|
UUIDKey = "uuid"
|
|
|
|
UUIDHeader = "X-Request-ID"
|
|
|
|
)
|
|
|
|
|
2022-03-23 13:54:44 +01:00
|
|
|
func init() { //nolint:gochecknoinits
|
|
|
|
zerolog.DefaultContextLogger = &log.Logger
|
|
|
|
}
|
|
|
|
|
2021-01-18 11:46:22 +01:00
|
|
|
// GetUUID gets the requests UUID from a request.
|
2022-01-20 13:11:46 +01:00
|
|
|
func GetUUID(r *http.Request) (string, bool) {
|
2022-01-14 13:48:41 +01:00
|
|
|
uuid, ok := hlog.IDFromRequest(r)
|
|
|
|
if !ok {
|
2022-01-20 13:11:46 +01:00
|
|
|
return "", false
|
2022-01-14 13:48:41 +01:00
|
|
|
}
|
|
|
|
|
2022-01-20 13:11:46 +01:00
|
|
|
return uuid.String(), true
|
2020-10-13 15:26:40 +02:00
|
|
|
}
|
|
|
|
|
2022-03-23 13:54:44 +01:00
|
|
|
// FromRequest returns a logger set from request.
|
2022-02-18 15:41:57 +01:00
|
|
|
// If no one could be found, it will return the global one.
|
2022-03-23 13:54:44 +01:00
|
|
|
func FromRequest(r *http.Request) *zerolog.Logger {
|
|
|
|
return hlog.FromRequest(r)
|
2020-10-13 15:26:40 +02:00
|
|
|
}
|
|
|
|
|
2022-03-23 13:54:44 +01:00
|
|
|
// FromCtx returns a logger set from ctx.
|
2022-02-18 15:41:57 +01:00
|
|
|
// If no one could be found, it will return the global one.
|
2022-03-23 13:54:44 +01:00
|
|
|
func FromCtx(ctx context.Context) *zerolog.Logger {
|
|
|
|
return zerolog.Ctx(ctx)
|
2022-01-24 11:45:27 +01:00
|
|
|
}
|
|
|
|
|
2023-02-24 10:07:06 +01:00
|
|
|
// RequestIDHandler looks in the header for an existing request id. Else it will create one.
|
|
|
|
func RequestIDHandler() func(http.Handler) http.Handler {
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
id := r.Header.Get(UUIDHeader)
|
|
|
|
|
|
|
|
if id != "" {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
log := zerolog.Ctx(ctx)
|
|
|
|
|
|
|
|
uuid, err := xid.FromString(id)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Err(err).Msg("couldnt parse uuid")
|
|
|
|
|
|
|
|
hlog.RequestIDHandler(UUIDKey, UUIDHeader)(next).ServeHTTP(w, r)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = hlog.CtxWithID(ctx, uuid)
|
|
|
|
r = r.WithContext(ctx)
|
|
|
|
|
|
|
|
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
|
|
|
|
return c.Str(UUIDKey, uuid.String())
|
|
|
|
})
|
|
|
|
|
|
|
|
w.Header().Set(UUIDHeader, uuid.String())
|
|
|
|
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
} else {
|
|
|
|
hlog.RequestIDHandler(UUIDKey, UUIDHeader)(next).ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-17 11:27:49 +01:00
|
|
|
func Handler(log zerolog.Logger) func(http.Handler) http.Handler {
|
2022-01-14 13:48:41 +01:00
|
|
|
return func(next http.Handler) http.Handler {
|
2022-01-17 11:27:49 +01:00
|
|
|
chain := alice.New(
|
|
|
|
hlog.NewHandler(log),
|
|
|
|
hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
|
|
|
|
hlog.FromRequest(r).Info().
|
|
|
|
Str("method", r.Method).
|
|
|
|
Str("proto", r.Proto).
|
|
|
|
Stringer("request-url", r.URL).
|
|
|
|
Int("status", status).
|
|
|
|
Int("size", size).
|
|
|
|
Dur("duration", duration).
|
|
|
|
Msg("")
|
|
|
|
}),
|
|
|
|
hlog.RemoteAddrHandler("remote"),
|
|
|
|
hlog.UserAgentHandler("user-agent"),
|
|
|
|
hlog.RefererHandler("referer"),
|
2023-02-24 10:07:06 +01:00
|
|
|
RequestIDHandler(),
|
2022-01-17 11:27:49 +01:00
|
|
|
).Then(next)
|
|
|
|
|
|
|
|
return chain
|
2022-01-14 13:48:41 +01:00
|
|
|
}
|
2020-10-13 15:26:40 +02:00
|
|
|
}
|