Skip to content

Commit 46cded8

Browse files
committed
connection: add opentelemetry gRPC tracing support
Create a new `WithOtelTracing` option to be used by gRPC client when connecting to the CSI server with `Connect`. This function adds a gRPC interceptor that will provide basic tracing of the gRPC calls.
1 parent b4d8781 commit 46cded8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+20465
-3
lines changed

connection/connection.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
"github.com/kubernetes-csi/csi-lib-utils/metrics"
2929
"github.com/kubernetes-csi/csi-lib-utils/protosanitizer"
30+
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
3031
"google.golang.org/grpc"
3132
"k8s.io/klog/v2"
3233
)
@@ -119,10 +120,18 @@ func withMetrics(metricsManager metrics.CSIMetricsManager) Option {
119120
}
120121
}
121122

123+
// WithOtelTracing enables the recording of traces on the gRPC calls with opentelemetry gRPC interceptor.
124+
func WithOtelTracing() Option {
125+
return func(o *options) {
126+
o.enableOtelTracing = true
127+
}
128+
}
129+
122130
type options struct {
123-
reconnect func() bool
124-
timeout time.Duration
125-
metricsManager metrics.CSIMetricsManager
131+
reconnect func() bool
132+
timeout time.Duration
133+
metricsManager metrics.CSIMetricsManager
134+
enableOtelTracing bool
126135
}
127136

128137
// connect is the internal implementation of Connect. It has more options to enable testing.
@@ -148,6 +157,9 @@ func connect(
148157
if o.metricsManager != nil {
149158
interceptors = append(interceptors, ExtendedCSIMetricsManager{o.metricsManager}.RecordMetricsClientInterceptor)
150159
}
160+
if o.enableOtelTracing {
161+
interceptors = append(interceptors, otelgrpc.UnaryClientInterceptor())
162+
}
151163
dialOptions = append(dialOptions, grpc.WithChainUnaryInterceptor(interceptors...))
152164

153165
unixPrefix := "unix://"

connection/connection_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"testing"
2828
"time"
2929

30+
"go.opentelemetry.io/otel/trace"
3031
"google.golang.org/grpc"
3132
"google.golang.org/grpc/codes"
3233
"google.golang.org/grpc/connectivity"
@@ -147,6 +148,21 @@ func TestConnectWithoutMetrics(t *testing.T) {
147148
}
148149
}
149150

151+
func TestConnectWithOtelTracing(t *testing.T) {
152+
tmp := tmpDir(t)
153+
defer os.RemoveAll(tmp)
154+
addr, stopServer := startServer(t, tmp, nil, nil, nil)
155+
defer stopServer()
156+
157+
conn, err := Connect(addr, metrics.NewCSIMetricsManager("fake.csi.driver.io"), WithOtelTracing())
158+
if assert.NoError(t, err, "connect via absolute path") &&
159+
assert.NotNil(t, conn, "got a connection") {
160+
assert.Equal(t, connectivity.Ready, conn.GetState(), "connection ready")
161+
err = conn.Close()
162+
assert.NoError(t, err, "closing connection")
163+
}
164+
}
165+
150166
func TestWaitForServer(t *testing.T) {
151167
tmp := tmpDir(t)
152168
defer os.RemoveAll(tmp)
@@ -491,3 +507,32 @@ func verifyMetricsError(t *testing.T, err error, metricToIgnore string) error {
491507

492508
return nil
493509
}
510+
511+
func TestConnectWithOtelGrpcInterceptorTraces(t *testing.T) {
512+
t.Logf("Running regular connection test")
513+
tmp := tmpDir(t)
514+
defer os.RemoveAll(tmp)
515+
// We have to have a real implementation of the gRPC call, otherwise the trace
516+
// interceptor is not called. The CSI identity service is used because it's simple.
517+
addr, stopServer := startServer(t, tmp, &identityServer{}, nil, nil)
518+
defer stopServer()
519+
520+
conn, err := Connect(addr, nil, WithOtelTracing())
521+
522+
if assert.NoError(t, err, "connect via absolute path") &&
523+
assert.NotNil(t, conn, "got a connection") {
524+
defer conn.Close()
525+
assert.Equal(t, connectivity.Ready, conn.GetState(), "connection ready")
526+
527+
identityClient := csi.NewIdentityClient(conn)
528+
ctx := context.Background()
529+
if _, err := identityClient.GetPluginInfo(ctx, &csi.GetPluginInfoRequest{}); assert.Error(t, err) {
530+
errStatus, _ := status.FromError(err)
531+
assert.Equal(t, codes.Unimplemented, errStatus.Code(), "not implemented")
532+
}
533+
534+
// First traceID is 00000000000000000000000000000000
535+
assert.Equal(t, "00000000000000000000000000000000", trace.SpanContextFromContext(ctx).TraceID().String())
536+
}
537+
538+
}

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ require (
66
github.com/container-storage-interface/spec v1.8.0
77
github.com/golang/protobuf v1.5.3
88
github.com/stretchr/testify v1.8.2
9+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.0
10+
go.opentelemetry.io/otel/trace v1.15.0
911
golang.org/x/net v0.12.0
1012
google.golang.org/grpc v1.54.0
1113
k8s.io/api v0.28.0-rc.0
@@ -21,6 +23,7 @@ require (
2123
github.com/davecgh/go-spew v1.1.1 // indirect
2224
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
2325
github.com/go-logr/logr v1.2.4 // indirect
26+
github.com/go-logr/stdr v1.2.2 // indirect
2427
github.com/go-openapi/jsonpointer v0.19.6 // indirect
2528
github.com/go-openapi/jsonreference v0.20.2 // indirect
2629
github.com/go-openapi/swag v0.22.3 // indirect
@@ -43,6 +46,8 @@ require (
4346
github.com/prometheus/common v0.44.0 // indirect
4447
github.com/prometheus/procfs v0.10.1 // indirect
4548
github.com/spf13/pflag v1.0.5 // indirect
49+
go.opentelemetry.io/otel v1.15.0 // indirect
50+
go.opentelemetry.io/otel/metric v0.38.0 // indirect
4651
golang.org/x/oauth2 v0.8.0 // indirect
4752
golang.org/x/sys v0.10.0 // indirect
4853
golang.org/x/term v0.10.0 // indirect

go.sum

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE=
2+
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
13
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
24
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
35
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
@@ -14,8 +16,11 @@ github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhF
1416
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
1517
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
1618
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
19+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
1720
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
1821
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
22+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
23+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
1924
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
2025
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
2126
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
@@ -93,6 +98,14 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ
9398
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
9499
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
95100
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
101+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.0 h1:pWlIooxHVVdetyXFDsuzfqV42lXVIDmVGBCHeaXzDyI=
102+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.41.0/go.mod h1:YjmsSWM1VTcWXFSgyrmLADPMZZohioz9onjgkikk59w=
103+
go.opentelemetry.io/otel v1.15.0 h1:NIl24d4eiLJPM0vKn4HjLYM+UZf6gSfi9Z+NmCxkWbk=
104+
go.opentelemetry.io/otel v1.15.0/go.mod h1:qfwLEbWhLPk5gyWrne4XnF0lC8wtywbuJbgfAE3zbek=
105+
go.opentelemetry.io/otel/metric v0.38.0 h1:vv/Nv/44S3GzMMmeUhaesBKsAenE6xLkTVWL+zuv30w=
106+
go.opentelemetry.io/otel/metric v0.38.0/go.mod h1:uAtxN5hl8aXh5irD8afBtSwQU5Zjg64WWSz6KheZxBg=
107+
go.opentelemetry.io/otel/trace v1.15.0 h1:5Fwje4O2ooOxkfyqI/kJwxWotggDLix4BSAvpE1wlpo=
108+
go.opentelemetry.io/otel/trace v1.15.0/go.mod h1:CUsmE2Ht1CRkvE8OsMESvraoZrrcgD1J2W8GV1ev0Y4=
96109
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
97110
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
98111
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=

0 commit comments

Comments
 (0)