mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 14:05:39 +00:00
8fa3026614
Request ID generation appears prominently in some services cumulative allocation rate, and while this does not eradicate this issue (the API still makes UUID objects), it does improve the overhead of this API and reduce the amount of garbage that it produces. Updates tailscale/corp#18266 Updates tailscale/corp#19054 Signed-off-by: James Tucker <james@tailscale.com>
75 lines
2.6 KiB
Go
75 lines
2.6 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package tsweb
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"tailscale.com/util/ctxkey"
|
|
"tailscale.com/util/fastuuid"
|
|
)
|
|
|
|
// RequestID is an opaque identifier for a HTTP request, used to correlate
|
|
// user-visible errors with backend server logs. The RequestID is typically
|
|
// threaded through an HTTP Middleware (WithRequestID) and then can be extracted
|
|
// by HTTP Handlers to include in their logs.
|
|
//
|
|
// RequestID is an opaque identifier for a HTTP request, used to correlate
|
|
// user-visible errors with backend server logs. If present in the context, the
|
|
// RequestID will be printed alongside the message text and logged in the
|
|
// AccessLogRecord.
|
|
//
|
|
// A RequestID has the format "REQ-1{ID}", and the ID should be treated as an
|
|
// opaque string. The current implementation uses a UUID.
|
|
type RequestID string
|
|
|
|
// String returns the string format of the request ID, for use in e.g. setting
|
|
// a [http.Header].
|
|
func (r RequestID) String() string {
|
|
return string(r)
|
|
}
|
|
|
|
// RequestIDKey stores and loads [RequestID] values within a [context.Context].
|
|
var RequestIDKey ctxkey.Key[RequestID]
|
|
|
|
// RequestIDHeader is a custom HTTP header that the WithRequestID middleware
|
|
// uses to determine whether to re-use a given request ID from the client
|
|
// or generate a new one.
|
|
const RequestIDHeader = "X-Tailscale-Request-Id"
|
|
|
|
// GenerateRequestID generates a new request ID with the current format.
|
|
func GenerateRequestID() RequestID {
|
|
// REQ-1 indicates the version of the RequestID pattern. It is
|
|
// currently arbitrary but allows for forward compatible
|
|
// transitions if needed.
|
|
return RequestID("REQ-1" + fastuuid.NewUUID().String())
|
|
}
|
|
|
|
// SetRequestID is an HTTP middleware that injects a RequestID in the
|
|
// *http.Request Context. The value of that request id is either retrieved from
|
|
// the RequestIDHeader or a randomly generated one if not exists. Inner
|
|
// handlers can retrieve this ID from the RequestIDFromContext function.
|
|
func SetRequestID(h http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var rid RequestID
|
|
if id := r.Header.Get(RequestIDHeader); id != "" {
|
|
rid = RequestID(id)
|
|
} else {
|
|
rid = GenerateRequestID()
|
|
}
|
|
ctx := RequestIDKey.WithValue(r.Context(), rid)
|
|
r = r.WithContext(ctx)
|
|
h.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// RequestIDFromContext retrieves the RequestID from context that can be set by
|
|
// the SetRequestID function.
|
|
//
|
|
// Deprecated: Use [RequestIDKey.Value] instead.
|
|
func RequestIDFromContext(ctx context.Context) RequestID {
|
|
return RequestIDKey.Value(ctx)
|
|
}
|