mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
feat: add unique ids to all HTTP requests (#3845)
This commit is contained in:
34
coderd/httpmw/requestid.go
Normal file
34
coderd/httpmw/requestid.go
Normal file
@ -0,0 +1,34 @@
|
||||
package httpmw
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"cdr.dev/slog"
|
||||
)
|
||||
|
||||
type requestIDContextKey struct{}
|
||||
|
||||
// RequestID returns the ID of the request.
|
||||
func RequestID(r *http.Request) uuid.UUID {
|
||||
rid, ok := r.Context().Value(requestIDContextKey{}).(uuid.UUID)
|
||||
if !ok {
|
||||
panic("developer error: request id middleware not provided")
|
||||
}
|
||||
return rid
|
||||
}
|
||||
|
||||
// AttachRequestID adds a request ID to each HTTP request.
|
||||
func AttachRequestID(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
rid := uuid.New()
|
||||
|
||||
ctx := context.WithValue(r.Context(), requestIDContextKey{}, rid)
|
||||
ctx = slog.With(ctx, slog.F("request_id", rid))
|
||||
|
||||
rw.Header().Set("X-Coder-Request-Id", rid.String())
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
33
coderd/httpmw/requestid_test.go
Normal file
33
coderd/httpmw/requestid_test.go
Normal file
@ -0,0 +1,33 @@
|
||||
package httpmw_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/coderd/httpmw"
|
||||
)
|
||||
|
||||
func TestRequestID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rtr := chi.NewRouter()
|
||||
rtr.Use(httpmw.AttachRequestID)
|
||||
rtr.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
rid := httpmw.RequestID(r)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(rid.String()))
|
||||
})
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
rw := httptest.NewRecorder()
|
||||
rtr.ServeHTTP(rw, r)
|
||||
|
||||
res := rw.Result()
|
||||
defer res.Body.Close()
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
require.NotEmpty(t, res.Header.Get("X-Coder-Request-ID"))
|
||||
require.NotEmpty(t, rw.Body.Bytes())
|
||||
}
|
Reference in New Issue
Block a user