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  }