chatai/auth_v2.169.0/internal/observability/request-logger.go

115 lines
3.0 KiB
Go

package observability
import (
"fmt"
"net/http"
"time"
chimiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/gofrs/uuid"
"github.com/sirupsen/logrus"
"github.com/supabase/auth/internal/conf"
"github.com/supabase/auth/internal/utilities"
)
func AddRequestID(globalConfig *conf.GlobalConfiguration) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
id := uuid.Must(uuid.NewV4()).String()
if globalConfig.API.RequestIDHeader != "" {
id = r.Header.Get(globalConfig.API.RequestIDHeader)
}
ctx := r.Context()
ctx = utilities.WithRequestID(ctx, id)
next.ServeHTTP(w, r.WithContext(ctx))
}
return http.HandlerFunc(fn)
}
}
func NewStructuredLogger(logger *logrus.Logger, config *conf.GlobalConfiguration) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/health" {
next.ServeHTTP(w, r)
} else {
chimiddleware.RequestLogger(&structuredLogger{logger, config})(next).ServeHTTP(w, r)
}
})
}
}
type structuredLogger struct {
Logger *logrus.Logger
Config *conf.GlobalConfiguration
}
func (l *structuredLogger) NewLogEntry(r *http.Request) chimiddleware.LogEntry {
referrer := utilities.GetReferrer(r, l.Config)
e := &logEntry{Entry: logrus.NewEntry(l.Logger)}
logFields := logrus.Fields{
"component": "api",
"method": r.Method,
"path": r.URL.Path,
"remote_addr": utilities.GetIPAddress(r),
"referer": referrer,
}
if reqID := utilities.GetRequestID(r.Context()); reqID != "" {
logFields["request_id"] = reqID
}
e.Entry = e.Entry.WithFields(logFields)
return e
}
// logEntry implements the chiMiddleware.LogEntry interface
type logEntry struct {
Entry *logrus.Entry
}
func (e *logEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) {
fields := logrus.Fields{
"status": status,
"duration": elapsed.Nanoseconds(),
}
errorCode := header.Get("x-sb-error-code")
if errorCode != "" {
fields["error_code"] = errorCode
}
entry := e.Entry.WithFields(fields)
entry.Info("request completed")
e.Entry = entry
}
func (e *logEntry) Panic(v interface{}, stack []byte) {
entry := e.Entry.WithFields(logrus.Fields{
"stack": string(stack),
"panic": fmt.Sprintf("%+v", v),
})
entry.Error("request panicked")
e.Entry = entry
}
func GetLogEntry(r *http.Request) *logEntry {
l, _ := chimiddleware.GetLogEntry(r).(*logEntry)
if l == nil {
return &logEntry{Entry: logrus.NewEntry(logrus.StandardLogger())}
}
return l
}
func LogEntrySetField(r *http.Request, key string, value interface{}) {
if l, ok := r.Context().Value(chimiddleware.LogEntryCtxKey).(*logEntry); ok {
l.Entry = l.Entry.WithField(key, value)
}
}
func LogEntrySetFields(r *http.Request, fields logrus.Fields) {
if l, ok := r.Context().Value(chimiddleware.LogEntryCtxKey).(*logEntry); ok {
l.Entry = l.Entry.WithFields(fields)
}
}