Last active
May 8, 2023 19:36
-
-
Save ribice/de64b7696fce94d7aa0d82fd785881aa to your computer and use it in GitHub Desktop.
Golang logging middleware
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package log | |
import ( | |
"context" | |
"net/http" | |
"net/http/httptest" | |
"net/http/httputil" | |
"os" | |
"time" | |
"github.com/go-chi/chi/middleware" | |
"github.com/rs/zerolog" | |
"github.com/ribice/api" | |
) | |
// Service represents zerolog logger | |
type Service struct { | |
l zerolog.Logger | |
} | |
// FromContext fetches context from logger | |
func FromContext(ctx context.Context) *zerolog.Event { | |
return ctx.Value(api.ContextKey("logger")).(*zerolog.Event) | |
} | |
// New instantiates new zero logger | |
func New() Service { | |
z := zerolog.New(os.Stdout) | |
zerolog.DurationFieldInteger = true | |
return Service{l: z} | |
} | |
// Middleware represents logging middleware | |
func (s Service) Middleware(next http.Handler) http.Handler { | |
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) | |
rec := httptest.NewRecorder() | |
req, _ := httputil.DumpRequest(r, r.Method != http.MethodGet) | |
ctx := r.Context() | |
logger := s.l.Info() | |
logger.Timestamp().Str("path", r.URL.EscapedPath()).Str("ip", r.RemoteAddr). | |
Interface("request_id", ctx.Value(middleware.RequestIDKey)).Bytes("request", req) | |
var body string | |
var queries []string | |
defer func(begin time.Time) { | |
status := ww.Status() | |
logger.Int64("took", time.Since(begin).Milliseconds()).Int("status", status). | |
Strs("queries", queries) | |
if status != http.StatusNotFound { | |
logger.Str("response", body) | |
} | |
if status >= 500 { | |
logger.Send() | |
} | |
}(time.Now()) | |
ctx = context.WithValue(ctx, api.ContextKey("logger"), logger) | |
ctx = context.WithValue(ctx, api.ContextKey("query"), &queries) | |
next.ServeHTTP(rec, r.WithContext(ctx)) | |
// this copies the recorded response to the response writer | |
for k, v := range rec.Header() { | |
ww.Header()[k] = v | |
} | |
body = rec.Body.String() | |
ww.WriteHeader(rec.Code) | |
rec.Body.WriteTo(ww) | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Should be:
if status >= 500 && ww.Status() < 600
Otherwise, it is always logging, right?