mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add unique ids to all HTTP requests (#3845)
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"cdr.dev/slog"
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/httpapi"
|
||||
"github.com/coder/coder/coderd/httpmw"
|
||||
)
|
||||
|
||||
type RequestParams struct {
|
||||
@@ -69,6 +70,7 @@ func InitRequest[T Auditable](w http.ResponseWriter, p *RequestParams) (*Request
|
||||
Action: p.Action,
|
||||
Diff: diffRaw,
|
||||
StatusCode: int32(sw.Status),
|
||||
RequestID: httpmw.RequestID(p.Request),
|
||||
})
|
||||
if err != nil {
|
||||
p.Log.Error(ctx, "export audit log", slog.Error(err))
|
||||
|
||||
@@ -155,6 +155,7 @@ func New(options *Options) *API {
|
||||
apiKeyMiddleware := httpmw.ExtractAPIKey(options.Database, oauthConfigs, false)
|
||||
|
||||
r.Use(
|
||||
httpmw.AttachRequestID,
|
||||
httpmw.Recover(api.Logger),
|
||||
httpmw.Logger(api.Logger),
|
||||
httpmw.Prometheus(options.PrometheusRegistry),
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
@@ -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