// Package middleware contains HTTP and ogen middleware used by the API layer. package middleware import ( "net/http" "time" "github.com/ogen-go/ogen/middleware" "go.uber.org/zap" ) // OgenLogging is an ogen middleware that logs request duration and outcome. func OgenLogging(log *zap.Logger) middleware.Middleware { return func(req middleware.Request, next func(req middleware.Request) (middleware.Response, error)) (middleware.Response, error) { lg := log.With(zap.String("op", req.OperationID)) start := time.Now() resp, err := next(req) dur := time.Since(start) if err != nil { lg.Error("request failed", zap.Duration("duration", dur), zap.Error(err)) } else { lg.Info("request completed", zap.Duration("duration", dur)) } return resp, err } } // statusRecorder captures the response status for HTTPLogging. type statusRecorder struct { http.ResponseWriter status int } func (r *statusRecorder) WriteHeader(code int) { r.status = code r.ResponseWriter.WriteHeader(code) } // HTTPLogging wraps the given http.Handler with a per-request log line. func HTTPLogging(log *zap.Logger, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() rec := &statusRecorder{ResponseWriter: w, status: 200} next.ServeHTTP(rec, r) log.Info("http", zap.String("method", r.Method), zap.String("path", r.URL.Path), zap.Int("status", rec.status), zap.Duration("duration", time.Since(start))) }) }