From: Dan Fuhry Date: Wed, 6 Aug 2025 03:22:56 +0000 (-0400) Subject: [http] add request IDs w/tracing support X-Git-Url: https://go.fuhry.dev/?a=commitdiff_plain;h=abc5ec7b9f6ecff22224a6adc72292d23a982173;p=runtime.git [http] add request IDs w/tracing support --- diff --git a/http/server.go b/http/server.go index e056d28..b845776 100644 --- a/http/server.go +++ b/http/server.go @@ -3,13 +3,16 @@ package http import ( "context" "crypto/tls" + "encoding/hex" "errors" "fmt" + "math/rand" "net" "net/http" "os" "regexp" "sync" + "time" "go.fuhry.dev/runtime/mtls" "go.fuhry.dev/runtime/utils/log" @@ -33,11 +36,12 @@ type VirtualHost struct { } type Listener struct { - Addr string `yaml:"listen"` - ProxyProtocol bool `yaml:"proxy_protocol"` - InsecureAddr string `yaml:"listen_insecure"` - Certificate string `yaml:"cert"` - VirtualHosts map[string]*VirtualHost `yaml:"virtual_hosts"` + Addr string `yaml:"listen"` + ProxyProtocol bool `yaml:"proxy_protocol"` + InsecureAddr string `yaml:"listen_insecure"` + Certificate string `yaml:"cert"` + TrustUpstreamRequestID bool `yaml:"trust_upstream_request_id"` + VirtualHosts map[string]*VirtualHost `yaml:"virtual_hosts"` } type Server struct { @@ -56,8 +60,10 @@ const ( kListener kListenAddr kSamlDefaults + kRequestID ) +var randSrc = rand.New(rand.NewSource(time.Now().UnixNano())) var portSpec = regexp.MustCompile(":[0-9]{1,5}$") var initHooks []initHook var routeParseFuncs []routeParseFunc @@ -237,6 +243,7 @@ func (l *Listener) NewHTTPServerWithContext(ctx context.Context) (*http.Server, lm := log.NewLoggingMiddlewareWithLogger( http.HandlerFunc(l.handle), logger.AppendPrefix(".access")) + lm.AddResponseHeader("x-request-id") server := &http.Server{ Addr: l.Addr, @@ -297,6 +304,14 @@ func (l *Listener) handle(w http.ResponseWriter, r *http.Request) { return } + reqIdCtx := r.Context() + rid := r.Header.Get("x-request-id") + if rid == "" || !l.TrustUpstreamRequestID { + rid = newRequestID() + } + w.Header().Set("x-request-id", rid) + reqIdCtx = context.WithValue(reqIdCtx, kRequestID, rid) + // make sure this host is known vhost, ok := l.VirtualHosts[r.Host] if !ok { @@ -309,7 +324,7 @@ func (l *Listener) handle(w http.ResponseWriter, r *http.Request) { } } - l.fulfill(w, r, vhost.Routes) + l.fulfill(w, r.WithContext(reqIdCtx), vhost.Routes) } func (l *Listener) fulfill(w http.ResponseWriter, r *http.Request, routes []*Route) { @@ -355,8 +370,18 @@ func (l *Listener) fulfill(w http.ResponseWriter, r *http.Request, routes []*Rou func LoggerFromContext(ctx context.Context) log.Logger { l := ctx.Value(kLogger) if logger, ok := l.(log.Logger); ok { + if v, ok := ctx.Value(kRequestID).(string); ok { + logger = logger.AppendPrefix(fmt.Sprintf("", v)) + } return logger } return nil } + +func newRequestID() string { + buf := make([]byte, 10) + _, _ = randSrc.Read(buf) + + return hex.EncodeToString(buf) +}