google.golang.org/grpc@v1.72.2/stats/opentelemetry/trace.go (about) 1 /* 2 * Copyright 2024 gRPC authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package opentelemetry 18 19 import ( 20 "sync/atomic" 21 22 "go.opentelemetry.io/otel/attribute" 23 otelcodes "go.opentelemetry.io/otel/codes" 24 "go.opentelemetry.io/otel/trace" 25 "google.golang.org/grpc/stats" 26 "google.golang.org/grpc/status" 27 ) 28 29 // populateSpan populates span information based on stats passed in, representing 30 // invariants of the RPC lifecycle. It ends the span, triggering its export. 31 // This function handles attempt spans on the client-side and call spans on the 32 // server-side. 33 func populateSpan(rs stats.RPCStats, ai *attemptInfo) { 34 if ai == nil || ai.traceSpan == nil { 35 // Shouldn't happen, tagRPC call comes before this function gets called 36 // which populates this information. 37 logger.Error("ctx passed into stats handler tracing event handling has no traceSpan present") 38 return 39 } 40 span := ai.traceSpan 41 42 switch rs := rs.(type) { 43 case *stats.Begin: 44 // Note: Go always added Client and FailFast attributes even though they are not 45 // defined by the OpenCensus gRPC spec. Thus, they are unimportant for 46 // correctness. 47 span.SetAttributes( 48 attribute.Bool("Client", rs.Client), 49 attribute.Bool("FailFast", rs.FailFast), 50 attribute.Int64("previous-rpc-attempts", int64(ai.previousRPCAttempts)), 51 attribute.Bool("transparent-retry", rs.IsTransparentRetryAttempt), 52 ) 53 // increment previous rpc attempts applicable for next attempt 54 atomic.AddUint32(&ai.previousRPCAttempts, 1) 55 case *stats.PickerUpdated: 56 span.AddEvent("Delayed LB pick complete") 57 case *stats.InPayload: 58 // message id - "must be calculated as two different counters starting 59 // from one for sent messages and one for received messages." 60 span.AddEvent("Inbound compressed message", trace.WithAttributes( 61 attribute.Int64("sequence-number", int64(ai.countRecvMsg)), 62 attribute.Int64("message-size", int64(rs.Length)), 63 attribute.Int64("message-size-compressed", int64(rs.CompressedLength)), 64 )) 65 ai.countRecvMsg++ 66 case *stats.OutPayload: 67 span.AddEvent("Outbound compressed message", trace.WithAttributes( 68 attribute.Int64("sequence-number", int64(ai.countSentMsg)), 69 attribute.Int64("message-size", int64(rs.Length)), 70 attribute.Int64("message-size-compressed", int64(rs.CompressedLength)), 71 )) 72 ai.countSentMsg++ 73 case *stats.End: 74 if rs.Error != nil { 75 s := status.Convert(rs.Error) 76 span.SetStatus(otelcodes.Error, s.Message()) 77 } else { 78 span.SetStatus(otelcodes.Ok, "Ok") 79 } 80 span.End() 81 } 82 }