github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/observability/tracing/client.go (about) 1 // Copyright 2022 Gravitational, Inc 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tracing 16 17 import ( 18 "context" 19 "sync/atomic" 20 21 "github.com/gravitational/trace" 22 "go.opentelemetry.io/otel/exporters/otlp/otlptrace" 23 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" 24 otlp "go.opentelemetry.io/proto/otlp/trace/v1" 25 "google.golang.org/grpc" 26 ) 27 28 // Client is a wrapper around an otlptrace.Client that provides a mechanism to 29 // close the underlying grpc.ClientConn. When an otlpgrpc.Client is constructed with 30 // the WithGRPCConn option, it is up to the caller to close the provided grpc.ClientConn. 31 // As such, we wrap and implement io.Closer to allow users to have a way to close the connection. 32 // 33 // In the event the client receives a trace.NotImplemented error when uploading spans, it will prevent 34 // any future spans from being sent. The server receiving the span is not going to change for the life 35 // of the grpc.ClientConn. In an effort to reduce wasted bandwidth, the client merely drops any spans in 36 // that case and returns nil. 37 type Client struct { 38 otlptrace.Client 39 conn *grpc.ClientConn 40 41 // notImplementedFlag is set to indicate that the server does 42 // accept traces. 43 notImplementedFlag int32 44 } 45 46 // NewClient returns a new Client that uses the provided grpc.ClientConn to 47 // connect to the OpenTelemetry exporter. 48 func NewClient(conn *grpc.ClientConn) *Client { 49 return &Client{ 50 Client: otlptracegrpc.NewClient(otlptracegrpc.WithGRPCConn(conn)), 51 conn: conn, 52 } 53 } 54 55 func (c *Client) UploadTraces(ctx context.Context, protoSpans []*otlp.ResourceSpans) error { 56 if len(protoSpans) == 0 || atomic.LoadInt32(&c.notImplementedFlag) == 1 { 57 return nil 58 } 59 60 err := c.Client.UploadTraces(ctx, protoSpans) 61 if err != nil && trace.IsNotImplemented(err) { 62 atomic.StoreInt32(&c.notImplementedFlag, 1) 63 return nil 64 } 65 66 return trace.Wrap(err) 67 } 68 69 // Close closes the underlying grpc.ClientConn. This is required since when 70 // using otlptracegrpc.WithGRPCConn the otlptrace.Client does not 71 // close the connection when Shutdown is called. 72 func (c *Client) Close() error { 73 return trace.Wrap(c.conn.Close()) 74 }