@@ -17,11 +17,14 @@ limitations under the License.
1717package handlers
1818
1919import (
20+ "context"
2021 "strconv"
2122 "time"
2223
2324 configPb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
2425 extProcPb "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3"
26+ "go.opentelemetry.io/otel"
27+ "go.opentelemetry.io/otel/propagation"
2528 "google.golang.org/protobuf/types/known/structpb"
2629
2730 "sigs.k8s.io/gateway-api-inference-extension/pkg/common"
@@ -37,7 +40,7 @@ const (
3740 defaultFairnessID = "default-flow"
3841)
3942
40- func (s * StreamingServer ) HandleRequestHeaders (reqCtx * RequestContext , req * extProcPb.ProcessingRequest_RequestHeaders ) error {
43+ func (s * StreamingServer ) HandleRequestHeaders (ctx context. Context , reqCtx * RequestContext , req * extProcPb.ProcessingRequest_RequestHeaders ) error {
4144 reqCtx .RequestReceivedTimestamp = time .Now ()
4245
4346 // an EoS in the request headers means this request has no body or trailers.
@@ -52,7 +55,7 @@ func (s *StreamingServer) HandleRequestHeaders(reqCtx *RequestContext, req *extP
5255 }
5356 reqCtx .TargetEndpoint = pod .GetIPAddress () + ":" + pod .GetPort ()
5457 reqCtx .RequestSize = 0
55- reqCtx .reqHeaderResp = s .generateRequestHeaderResponse (reqCtx )
58+ reqCtx .reqHeaderResp = s .generateRequestHeaderResponse (ctx , reqCtx )
5659 return nil
5760 }
5861
@@ -91,7 +94,7 @@ func (s *StreamingServer) generateRequestBodyResponses(requestBodyBytes []byte)
9194 return responses
9295}
9396
94- func (s * StreamingServer ) generateRequestHeaderResponse (reqCtx * RequestContext ) * extProcPb.ProcessingResponse {
97+ func (s * StreamingServer ) generateRequestHeaderResponse (ctx context. Context , reqCtx * RequestContext ) * extProcPb.ProcessingResponse {
9598 // The Endpoint Picker supports two approaches to communicating the target endpoint, as a request header
9699 // and as an unstructure ext-proc response metadata key/value pair. This enables different integration
97100 // options for gateway providers.
@@ -101,7 +104,7 @@ func (s *StreamingServer) generateRequestHeaderResponse(reqCtx *RequestContext)
101104 Response : & extProcPb.CommonResponse {
102105 ClearRouteCache : true ,
103106 HeaderMutation : & extProcPb.HeaderMutation {
104- SetHeaders : s .generateHeaders (reqCtx ),
107+ SetHeaders : s .generateHeaders (ctx , reqCtx ),
105108 },
106109 },
107110 },
@@ -110,7 +113,7 @@ func (s *StreamingServer) generateRequestHeaderResponse(reqCtx *RequestContext)
110113 }
111114}
112115
113- func (s * StreamingServer ) generateHeaders (reqCtx * RequestContext ) []* configPb.HeaderValueOption {
116+ func (s * StreamingServer ) generateHeaders (ctx context. Context , reqCtx * RequestContext ) []* configPb.HeaderValueOption {
114117 // can likely refactor these two bespoke headers to be updated in PostDispatch, to centralize logic.
115118 headers := []* configPb.HeaderValueOption {
116119 {
@@ -131,6 +134,19 @@ func (s *StreamingServer) generateHeaders(reqCtx *RequestContext) []*configPb.He
131134 })
132135 }
133136
137+ // Inject trace context headers for propagation to downstream services
138+ traceHeaders := make (map [string ]string )
139+ propagator := otel .GetTextMapPropagator ()
140+ propagator .Inject (ctx , propagation .MapCarrier (traceHeaders ))
141+ for key , value := range traceHeaders {
142+ headers = append (headers , & configPb.HeaderValueOption {
143+ Header : & configPb.HeaderValue {
144+ Key : key ,
145+ RawValue : []byte (value ),
146+ },
147+ })
148+ }
149+
134150 // Include any non-system-owned headers.
135151 for key , value := range reqCtx .Request .Headers {
136152 if request .IsSystemOwnedHeader (key ) {
0 commit comments