google.golang.org/grpc@v1.72.2/stats/opentelemetry/csm/observability.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 csm
    20  
    21  import (
    22  	"context"
    23  	"net/url"
    24  
    25  	"google.golang.org/grpc"
    26  	"google.golang.org/grpc/internal"
    27  	"google.golang.org/grpc/stats/opentelemetry"
    28  	otelinternal "google.golang.org/grpc/stats/opentelemetry/internal"
    29  )
    30  
    31  // EnableObservability sets up CSM Observability for the binary globally.
    32  //
    33  // The CSM Stats Plugin is instantiated with local labels and metadata exchange
    34  // labels pulled from the environment, and emits metadata exchange labels from
    35  // the peer and local labels. Context timeouts do not trigger an error, but set
    36  // certain labels to "unknown".
    37  //
    38  // This function is not thread safe, and should only be invoked once in main
    39  // before any channels or servers are created. Returns a cleanup function to be
    40  // deferred in main.
    41  func EnableObservability(ctx context.Context, options opentelemetry.Options) func() {
    42  	csmPluginOption := newPluginOption(ctx)
    43  	clientSideOTelWithCSM := dialOptionWithCSMPluginOption(options, csmPluginOption)
    44  	clientSideOTel := opentelemetry.DialOption(options)
    45  	internal.AddGlobalPerTargetDialOptions.(func(opt any))(&perTargetDialOption{
    46  		clientSideOTelWithCSM: clientSideOTelWithCSM,
    47  		clientSideOTel:        clientSideOTel,
    48  	})
    49  
    50  	serverSideOTelWithCSM := serverOptionWithCSMPluginOption(options, csmPluginOption)
    51  	internal.AddGlobalServerOptions.(func(opt ...grpc.ServerOption))(serverSideOTelWithCSM)
    52  
    53  	return func() {
    54  		internal.ClearGlobalServerOptions()
    55  		internal.ClearGlobalPerTargetDialOptions()
    56  	}
    57  }
    58  
    59  type perTargetDialOption struct {
    60  	clientSideOTelWithCSM grpc.DialOption
    61  	clientSideOTel        grpc.DialOption
    62  }
    63  
    64  func (o *perTargetDialOption) DialOptionForTarget(parsedTarget url.URL) grpc.DialOption {
    65  	if determineTargetCSM(&parsedTarget) {
    66  		return o.clientSideOTelWithCSM
    67  	}
    68  	return o.clientSideOTel
    69  }
    70  
    71  func dialOptionWithCSMPluginOption(options opentelemetry.Options, po otelinternal.PluginOption) grpc.DialOption {
    72  	options.MetricsOptions.OptionalLabels = []string{"csm.service_name", "csm.service_namespace_name"} // Attach the two xDS Optional Labels for this component to not filter out.
    73  	return dialOptionSetCSM(options, po)
    74  }
    75  
    76  func dialOptionSetCSM(options opentelemetry.Options, po otelinternal.PluginOption) grpc.DialOption {
    77  	otelinternal.SetPluginOption.(func(options *opentelemetry.Options, po otelinternal.PluginOption))(&options, po)
    78  	return opentelemetry.DialOption(options)
    79  }
    80  
    81  func serverOptionWithCSMPluginOption(options opentelemetry.Options, po otelinternal.PluginOption) grpc.ServerOption {
    82  	otelinternal.SetPluginOption.(func(options *opentelemetry.Options, po otelinternal.PluginOption))(&options, po)
    83  	return opentelemetry.ServerOption(options)
    84  }