Skip to content

Commit 9f19153

Browse files
authored
Merge pull request #20043 from dims/automated-cherry-pick-of-#20017-upstream-release-3.6-take-2
Semi-Automated cherry pick of #20017 upstream release 3.6 ( was Update go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc to work with v0.61.0 )
2 parents 7b35142 + 5baf45e commit 9f19153

File tree

2 files changed

+68
-10
lines changed

2 files changed

+68
-10
lines changed

server/etcdserver/api/v3rpc/grpc.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ func Server(s *etcdserver.EtcdServer, tls *tls.Config, interceptor grpc.UnarySer
6767
}
6868

6969
if s.Cfg.EnableDistributedTracing {
70-
chainUnaryInterceptors = append(chainUnaryInterceptors, otelgrpc.UnaryServerInterceptor(s.Cfg.TracerOptions...))
71-
chainStreamInterceptors = append(chainStreamInterceptors, otelgrpc.StreamServerInterceptor(s.Cfg.TracerOptions...))
70+
opts = append(opts, grpc.StatsHandler(otelgrpc.NewServerHandler(s.Cfg.TracerOptions...)))
7271
}
7372

7473
opts = append(opts, grpc.ChainUnaryInterceptor(chainUnaryInterceptors...))

tests/integration/tracing_test.go

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,48 @@ import (
3838
func TestTracing(t *testing.T) {
3939
testutil.SkipTestIfShortMode(t,
4040
"Wal creation tests are depending on embedded etcd server so are integration-level tests.")
41+
42+
// Test Unary RPC tracing
43+
t.Run("UnaryRPC", func(t *testing.T) {
44+
testRPCTracing(t, "UnaryRPC", containsUnaryRPCSpan, func(cli *clientv3.Client) error {
45+
// make a request with the instrumented client
46+
resp, err := cli.Get(context.TODO(), "key")
47+
require.NoError(t, err)
48+
require.Empty(t, resp.Kvs)
49+
return nil
50+
})
51+
})
52+
53+
// Test Stream RPC tracing
54+
t.Run("StreamRPC", func(t *testing.T) {
55+
testRPCTracing(t, "StreamRPC", containsStreamRPCSpan, func(cli *clientv3.Client) error {
56+
// Create a context with a reasonable timeout
57+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
58+
defer cancel()
59+
60+
// Create a watch channel
61+
watchChan := cli.Watch(ctx, "watch-key")
62+
63+
// Put a value to trigger the watch
64+
_, err := cli.Put(context.TODO(), "watch-key", "watch-value")
65+
require.NoError(t, err)
66+
67+
// Wait for watch event
68+
select {
69+
case watchResp := <-watchChan:
70+
require.NoError(t, watchResp.Err())
71+
require.Len(t, watchResp.Events, 1)
72+
t.Log("Received watch event successfully")
73+
case <-time.After(5 * time.Second):
74+
t.Fatal("Timed out waiting for watch event")
75+
}
76+
return nil
77+
})
78+
})
79+
}
80+
81+
// testRPCTracing is a common test function for both Unary and Stream RPC tracing
82+
func testRPCTracing(t *testing.T, testName string, filterFunc func(*traceservice.ExportTraceServiceRequest) bool, clientAction func(*clientv3.Client) error) {
4183
// set up trace collector
4284
listener, err := net.Listen("tcp", "localhost:")
4385
require.NoError(t, err)
@@ -48,7 +90,7 @@ func TestTracing(t *testing.T) {
4890
srv := grpc.NewServer()
4991
traceservice.RegisterTraceServiceServer(srv, &traceServer{
5092
traceFound: traceFound,
51-
filterFunc: containsNodeListSpan,
93+
filterFunc: filterFunc,
5294
})
5395

5496
go srv.Serve(listener)
@@ -89,8 +131,7 @@ func TestTracing(t *testing.T) {
89131
}
90132

91133
dialOptions := []grpc.DialOption{
92-
grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor(tracingOpts...)),
93-
grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor(tracingOpts...)),
134+
grpc.WithStatsHandler(otelgrpc.NewClientHandler(tracingOpts...)),
94135
}
95136
ccfg := clientv3.Config{DialOptions: dialOptions, Endpoints: []string{cfg.AdvertiseClientUrls[0].String()}}
96137
cli, err := integration.NewClient(t, ccfg)
@@ -100,21 +141,21 @@ func TestTracing(t *testing.T) {
100141
}
101142
defer cli.Close()
102143

103-
// make a request with the instrumented client
104-
resp, err := cli.Get(context.TODO(), "key")
144+
// Execute the client action (either Unary or Stream RPC)
145+
err = clientAction(cli)
105146
require.NoError(t, err)
106-
require.Empty(t, resp.Kvs)
107147

108148
// Wait for a span to be recorded from our request
109149
select {
110150
case <-traceFound:
151+
t.Logf("%s trace found", testName)
111152
return
112153
case <-time.After(30 * time.Second):
113154
t.Fatal("Timed out waiting for trace")
114155
}
115156
}
116157

117-
func containsNodeListSpan(req *traceservice.ExportTraceServiceRequest) bool {
158+
func containsUnaryRPCSpan(req *traceservice.ExportTraceServiceRequest) bool {
118159
for _, resourceSpans := range req.GetResourceSpans() {
119160
for _, attr := range resourceSpans.GetResource().GetAttributes() {
120161
if attr.GetKey() != "service.name" && attr.GetValue().GetStringValue() != "integration-test-tracing" {
@@ -132,6 +173,20 @@ func containsNodeListSpan(req *traceservice.ExportTraceServiceRequest) bool {
132173
return false
133174
}
134175

176+
// containsStreamRPCSpan checks for Watch/Watch spans in trace data
177+
func containsStreamRPCSpan(req *traceservice.ExportTraceServiceRequest) bool {
178+
for _, resourceSpans := range req.GetResourceSpans() {
179+
for _, scoped := range resourceSpans.GetScopeSpans() {
180+
for _, span := range scoped.GetSpans() {
181+
if span.GetName() == "etcdserverpb.Watch/Watch" {
182+
return true
183+
}
184+
}
185+
}
186+
}
187+
return false
188+
}
189+
135190
// traceServer implements TracesServiceServer
136191
type traceServer struct {
137192
traceFound chan struct{}
@@ -142,7 +197,11 @@ type traceServer struct {
142197
func (t *traceServer) Export(ctx context.Context, req *traceservice.ExportTraceServiceRequest) (*traceservice.ExportTraceServiceResponse, error) {
143198
emptyValue := traceservice.ExportTraceServiceResponse{}
144199
if t.filterFunc(req) {
145-
t.traceFound <- struct{}{}
200+
select {
201+
case t.traceFound <- struct{}{}:
202+
default:
203+
// Channel already notified
204+
}
146205
}
147206
return &emptyValue, nil
148207
}

0 commit comments

Comments
 (0)