google.golang.org/grpc@v1.72.2/stats/opentelemetry/grpc_trace_bin_propagator.go (about) 1 /* 2 * 3 * Copyright 2024 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package opentelemetry 20 21 import ( 22 "context" 23 24 otelpropagation "go.opentelemetry.io/otel/propagation" 25 oteltrace "go.opentelemetry.io/otel/trace" 26 ) 27 28 // gRPCTraceBinHeaderKey is the gRPC metadata header key `grpc-trace-bin` used 29 // to propagate trace context in binary format. 30 const grpcTraceBinHeaderKey = "grpc-trace-bin" 31 32 // GRPCTraceBinPropagator is an OpenTelemetry TextMapPropagator which is used 33 // to extract and inject trace context data from and into headers exchanged by 34 // gRPC applications. It propagates trace data in binary format using the 35 // `grpc-trace-bin` header. 36 type GRPCTraceBinPropagator struct{} 37 38 // Inject sets OpenTelemetry span context from the Context into the carrier as 39 // a `grpc-trace-bin` header if span context is valid. 40 // 41 // If span context is not valid, it returns without setting `grpc-trace-bin` 42 // header. 43 func (GRPCTraceBinPropagator) Inject(ctx context.Context, carrier otelpropagation.TextMapCarrier) { 44 sc := oteltrace.SpanFromContext(ctx) 45 if !sc.SpanContext().IsValid() { 46 return 47 } 48 49 bd := toBinary(sc.SpanContext()) 50 carrier.Set(grpcTraceBinHeaderKey, string(bd)) 51 } 52 53 // Extract reads OpenTelemetry span context from the `grpc-trace-bin` header of 54 // carrier into the provided context, if present. 55 // 56 // If a valid span context is retrieved from `grpc-trace-bin`, it returns a new 57 // context containing the extracted OpenTelemetry span context marked as 58 // remote. 59 // 60 // If `grpc-trace-bin` header is not present, it returns the context as is. 61 func (GRPCTraceBinPropagator) Extract(ctx context.Context, carrier otelpropagation.TextMapCarrier) context.Context { 62 h := carrier.Get(grpcTraceBinHeaderKey) 63 if h == "" { 64 return ctx 65 } 66 67 sc, ok := fromBinary([]byte(h)) 68 if !ok { 69 return ctx 70 } 71 return oteltrace.ContextWithRemoteSpanContext(ctx, sc) 72 } 73 74 // Fields returns the keys whose values are set with Inject. 75 // 76 // GRPCTraceBinPropagator always returns a slice containing only 77 // `grpc-trace-bin` key because it only sets the `grpc-trace-bin` header for 78 // propagating trace context. 79 func (GRPCTraceBinPropagator) Fields() []string { 80 return []string{grpcTraceBinHeaderKey} 81 } 82 83 // toBinary returns the binary format representation of a SpanContext. 84 // 85 // If sc is the zero value, returns nil. 86 func toBinary(sc oteltrace.SpanContext) []byte { 87 if sc.Equal(oteltrace.SpanContext{}) { 88 return nil 89 } 90 var b [29]byte 91 traceID := oteltrace.TraceID(sc.TraceID()) 92 copy(b[2:18], traceID[:]) 93 b[18] = 1 94 spanID := oteltrace.SpanID(sc.SpanID()) 95 copy(b[19:27], spanID[:]) 96 b[27] = 2 97 b[28] = byte(oteltrace.TraceFlags(sc.TraceFlags())) 98 return b[:] 99 } 100 101 // fromBinary returns the SpanContext represented by b with Remote set to true. 102 // 103 // It returns with zero value SpanContext and false, if any of the 104 // below condition is not satisfied: 105 // - Valid header: len(b) = 29 106 // - Valid version: b[0] = 0 107 // - Valid traceID prefixed with 0: b[1] = 0 108 // - Valid spanID prefixed with 1: b[18] = 1 109 // - Valid traceFlags prefixed with 2: b[27] = 2 110 func fromBinary(b []byte) (oteltrace.SpanContext, bool) { 111 if len(b) != 29 || b[0] != 0 || b[1] != 0 || b[18] != 1 || b[27] != 2 { 112 return oteltrace.SpanContext{}, false 113 } 114 115 return oteltrace.SpanContext{}.WithTraceID( 116 oteltrace.TraceID(b[2:18])).WithSpanID( 117 oteltrace.SpanID(b[19:27])).WithTraceFlags( 118 oteltrace.TraceFlags(b[28])).WithRemote(true), true 119 }