google.golang.org/grpc@v1.72.2/stats/opentelemetry/internal/tracing/carrier.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 tracing implements the OpenTelemetry carrier for context propagation
    20  // in gRPC tracing.
    21  package tracing
    22  
    23  import (
    24  	"context"
    25  
    26  	"google.golang.org/grpc/grpclog"
    27  	"google.golang.org/grpc/metadata"
    28  )
    29  
    30  var logger = grpclog.Component("otel-plugin")
    31  
    32  // IncomingCarrier is a TextMapCarrier that uses incoming `context.Context` to
    33  // retrieve any propagated key-value pairs in text format.
    34  type IncomingCarrier struct {
    35  	ctx context.Context
    36  }
    37  
    38  // NewIncomingCarrier creates a new `IncomingCarrier` with the given context.
    39  // The incoming carrier should be used with propagator's `Extract()` method in
    40  // the incoming rpc path.
    41  func NewIncomingCarrier(ctx context.Context) *IncomingCarrier {
    42  	return &IncomingCarrier{ctx: ctx}
    43  }
    44  
    45  // Get returns the string value associated with the passed key from the
    46  // carrier's incoming context metadata.
    47  //
    48  // It returns an empty string if the key is not present in the carrier's
    49  // context or if the value associated with the key is empty.
    50  //
    51  // If multiple values are present for a key, it returns the last one.
    52  func (c *IncomingCarrier) Get(key string) string {
    53  	values := metadata.ValueFromIncomingContext(c.ctx, key)
    54  	if len(values) == 0 {
    55  		return ""
    56  	}
    57  	return values[len(values)-1]
    58  }
    59  
    60  // Set just logs an error. It implements the `TextMapCarrier` interface but
    61  // should not be used with `IncomingCarrier`.
    62  func (c *IncomingCarrier) Set(string, string) {
    63  	logger.Error("Set() should not be used with IncomingCarrier.")
    64  }
    65  
    66  // Keys returns the keys stored in the carrier's context metadata. It returns
    67  // keys from incoming context metadata.
    68  func (c *IncomingCarrier) Keys() []string {
    69  	md, ok := metadata.FromIncomingContext(c.ctx)
    70  	if !ok {
    71  		return nil
    72  	}
    73  	keys := make([]string, 0, len(md))
    74  	for key := range md {
    75  		keys = append(keys, key)
    76  	}
    77  	return keys
    78  }
    79  
    80  // Context returns the underlying context associated with the
    81  // `IncomingCarrier“.
    82  func (c *IncomingCarrier) Context() context.Context {
    83  	return c.ctx
    84  }
    85  
    86  // OutgoingCarrier is a TextMapCarrier that uses outgoing `context.Context` to
    87  // store any propagated key-value pairs in text format.
    88  type OutgoingCarrier struct {
    89  	ctx context.Context
    90  }
    91  
    92  // NewOutgoingCarrier creates a new Carrier with the given context. The
    93  // outgoing carrier should be used with propagator's `Inject()` method in the
    94  // outgoing rpc path.
    95  func NewOutgoingCarrier(ctx context.Context) *OutgoingCarrier {
    96  	return &OutgoingCarrier{ctx: ctx}
    97  }
    98  
    99  // Get just logs an error and returns an empty string. It implements the
   100  // `TextMapCarrier` interface but should not be used with `OutgoingCarrier`.
   101  func (c *OutgoingCarrier) Get(string) string {
   102  	logger.Error("Get() should not be used with `OutgoingCarrier`")
   103  	return ""
   104  }
   105  
   106  // Set stores the key-value pair in the carrier's outgoing context metadata.
   107  //
   108  // If the key already exists, given value is appended to the last.
   109  func (c *OutgoingCarrier) Set(key, value string) {
   110  	c.ctx = metadata.AppendToOutgoingContext(c.ctx, key, value)
   111  }
   112  
   113  // Keys returns the keys stored in the carrier's context metadata. It returns
   114  // keys from outgoing context metadata.
   115  func (c *OutgoingCarrier) Keys() []string {
   116  	md, ok := metadata.FromOutgoingContext(c.ctx)
   117  	if !ok {
   118  		return nil
   119  	}
   120  	keys := make([]string, 0, len(md))
   121  	for key := range md {
   122  		keys = append(keys, key)
   123  	}
   124  	return keys
   125  }
   126  
   127  // Context returns the underlying context associated with the
   128  // `OutgoingCarrier“.
   129  func (c *OutgoingCarrier) Context() context.Context {
   130  	return c.ctx
   131  }