Skip to content

Commit 3146f0c

Browse files
authored
feat(tracing): Add Store, P2P and Config tracing (#2972)
<!-- Please read and fill out this form before submitting your PR. Please make sure you have reviewed our contributors guide before submitting your first PR. NOTE: PR titles should follow semantic commits: https://www.conventionalcommits.org/en/v1.0.0/ --> ## Overview Adding additional tracing within `NewServiceHandler` <!-- Please provide an explanation of the PR, including the appropriate context, background, goal, and rationale. If there is an issue with this information, please provide a tl;dr and link the issue. Ex: Closes #<issue number> -->
1 parent 34034c1 commit 3146f0c

File tree

5 files changed

+798
-12
lines changed

5 files changed

+798
-12
lines changed

execution/grpc/go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ require (
77
connectrpc.com/grpcreflect v1.3.0
88
github.com/evstack/ev-node v1.0.0-beta.11
99
github.com/evstack/ev-node/core v1.0.0-beta.5
10-
golang.org/x/net v0.49.0
11-
google.golang.org/protobuf v1.36.11
10+
golang.org/x/net v0.47.0
11+
google.golang.org/protobuf v1.36.10
1212
)
1313

14-
require golang.org/x/text v0.33.0 // indirect
14+
require golang.org/x/text v0.31.0 // indirect

execution/grpc/go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ github.com/evstack/ev-node/core v1.0.0-beta.5 h1:lgxE8XiF3U9pcFgh7xuKMgsOGvLBGRy
88
github.com/evstack/ev-node/core v1.0.0-beta.5/go.mod h1:n2w/LhYQTPsi48m6lMj16YiIqsaQw6gxwjyJvR+B3sY=
99
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
1010
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
11-
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
12-
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
13-
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
14-
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
15-
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
16-
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
11+
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
12+
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
13+
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
14+
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
15+
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
16+
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=

pkg/rpc/server/server.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,15 @@ func NewServiceHandler(
378378
config config.Config,
379379
bestKnown BestKnownHeightProvider,
380380
) (http.Handler, error) {
381-
storeServer := NewStoreServer(store, headerStore, dataStore, logger)
382-
p2pServer := NewP2PServer(peerManager)
383-
configServer := NewConfigServer(config, proposerAddress, logger)
381+
var storeServer rpc.StoreServiceHandler = NewStoreServer(store, headerStore, dataStore, logger)
382+
var p2pServer rpc.P2PServiceHandler = NewP2PServer(peerManager)
383+
var configServer rpc.ConfigServiceHandler = NewConfigServer(config, proposerAddress, logger)
384+
385+
if config.Instrumentation.IsTracingEnabled() {
386+
storeServer = WithTracingStoreServer(storeServer)
387+
p2pServer = WithTracingP2PServer(p2pServer)
388+
configServer = WithTracingConfigServer(configServer)
389+
}
384390

385391
mux := http.NewServeMux()
386392

pkg/rpc/server/tracing.go

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
package server
2+
3+
import (
4+
"context"
5+
"encoding/hex"
6+
7+
"connectrpc.com/connect"
8+
"go.opentelemetry.io/otel"
9+
"go.opentelemetry.io/otel/attribute"
10+
"go.opentelemetry.io/otel/codes"
11+
"go.opentelemetry.io/otel/trace"
12+
"google.golang.org/protobuf/types/known/emptypb"
13+
14+
pb "github.com/evstack/ev-node/types/pb/evnode/v1"
15+
"github.com/evstack/ev-node/types/pb/evnode/v1/v1connect"
16+
)
17+
18+
// tracedStoreServer decorates a StoreServiceHandler with OpenTelemetry spans.
19+
type tracedStoreServer struct {
20+
inner v1connect.StoreServiceHandler
21+
tracer trace.Tracer
22+
}
23+
24+
// WithTracingStoreServer decorates the provided store service handler with tracing spans.
25+
func WithTracingStoreServer(inner v1connect.StoreServiceHandler) v1connect.StoreServiceHandler {
26+
return &tracedStoreServer{
27+
inner: inner,
28+
tracer: otel.Tracer("ev-node/store-service"),
29+
}
30+
}
31+
32+
func (t *tracedStoreServer) GetBlock(
33+
ctx context.Context,
34+
req *connect.Request[pb.GetBlockRequest],
35+
) (*connect.Response[pb.GetBlockResponse], error) {
36+
var attrs []attribute.KeyValue
37+
switch identifier := req.Msg.Identifier.(type) {
38+
case *pb.GetBlockRequest_Height:
39+
attrs = append(attrs, attribute.Int64("height", int64(identifier.Height)))
40+
case *pb.GetBlockRequest_Hash:
41+
if identifier.Hash != nil {
42+
attrs = append(attrs, attribute.String("hash", hex.EncodeToString(identifier.Hash)))
43+
}
44+
}
45+
46+
ctx, span := t.tracer.Start(ctx, "StoreService.GetBlock", trace.WithAttributes(attrs...))
47+
defer span.End()
48+
49+
res, err := t.inner.GetBlock(ctx, req)
50+
if err != nil {
51+
span.RecordError(err)
52+
span.SetStatus(codes.Error, err.Error())
53+
return nil, err
54+
}
55+
56+
span.SetAttributes(
57+
attribute.Bool("found", res.Msg.Block != nil),
58+
)
59+
if res.Msg.Block != nil && res.Msg.Block.Data != nil {
60+
totalSize := 0
61+
for _, tx := range res.Msg.Block.Data.Txs {
62+
totalSize += len(tx)
63+
}
64+
span.SetAttributes(
65+
attribute.Int("block_size_bytes", totalSize),
66+
attribute.Int("tx_count", len(res.Msg.Block.Data.Txs)),
67+
)
68+
}
69+
return res, nil
70+
}
71+
72+
func (t *tracedStoreServer) GetState(
73+
ctx context.Context,
74+
req *connect.Request[emptypb.Empty],
75+
) (*connect.Response[pb.GetStateResponse], error) {
76+
ctx, span := t.tracer.Start(ctx, "StoreService.GetState")
77+
defer span.End()
78+
79+
res, err := t.inner.GetState(ctx, req)
80+
if err != nil {
81+
span.RecordError(err)
82+
span.SetStatus(codes.Error, err.Error())
83+
return nil, err
84+
}
85+
86+
if res.Msg.State != nil {
87+
span.SetAttributes(
88+
attribute.Int64("height", int64(res.Msg.State.LastBlockHeight)),
89+
attribute.String("app_hash", hex.EncodeToString(res.Msg.State.AppHash)),
90+
attribute.Int64("da_height", int64(res.Msg.State.DaHeight)),
91+
)
92+
}
93+
return res, nil
94+
}
95+
96+
func (t *tracedStoreServer) GetMetadata(
97+
ctx context.Context,
98+
req *connect.Request[pb.GetMetadataRequest],
99+
) (*connect.Response[pb.GetMetadataResponse], error) {
100+
ctx, span := t.tracer.Start(ctx, "StoreService.GetMetadata",
101+
trace.WithAttributes(
102+
attribute.String("key", req.Msg.Key),
103+
),
104+
)
105+
defer span.End()
106+
107+
res, err := t.inner.GetMetadata(ctx, req)
108+
if err != nil {
109+
span.RecordError(err)
110+
span.SetStatus(codes.Error, err.Error())
111+
return nil, err
112+
}
113+
114+
span.SetAttributes(
115+
attribute.Int("value_size_bytes", len(res.Msg.Value)),
116+
)
117+
return res, nil
118+
}
119+
120+
func (t *tracedStoreServer) GetGenesisDaHeight(
121+
ctx context.Context,
122+
req *connect.Request[emptypb.Empty],
123+
) (*connect.Response[pb.GetGenesisDaHeightResponse], error) {
124+
ctx, span := t.tracer.Start(ctx, "StoreService.GetGenesisDaHeight")
125+
defer span.End()
126+
127+
res, err := t.inner.GetGenesisDaHeight(ctx, req)
128+
if err != nil {
129+
span.RecordError(err)
130+
span.SetStatus(codes.Error, err.Error())
131+
return nil, err
132+
}
133+
134+
span.SetAttributes(
135+
attribute.Int64("genesis_da_height", int64(res.Msg.Height)),
136+
)
137+
return res, nil
138+
}
139+
140+
func (t *tracedStoreServer) GetP2PStoreInfo(
141+
ctx context.Context,
142+
req *connect.Request[emptypb.Empty],
143+
) (*connect.Response[pb.GetP2PStoreInfoResponse], error) {
144+
ctx, span := t.tracer.Start(ctx, "StoreService.GetP2PStoreInfo")
145+
defer span.End()
146+
147+
res, err := t.inner.GetP2PStoreInfo(ctx, req)
148+
if err != nil {
149+
span.RecordError(err)
150+
span.SetStatus(codes.Error, err.Error())
151+
return nil, err
152+
}
153+
154+
span.SetAttributes(
155+
attribute.Int("store_count", len(res.Msg.Stores)),
156+
)
157+
return res, nil
158+
}
159+
160+
// tracedP2PServer decorates a P2PServiceHandler with OpenTelemetry spans.
161+
type tracedP2PServer struct {
162+
inner v1connect.P2PServiceHandler
163+
tracer trace.Tracer
164+
}
165+
166+
// WithTracingP2PServer decorates the provided P2P service handler with tracing spans.
167+
func WithTracingP2PServer(inner v1connect.P2PServiceHandler) v1connect.P2PServiceHandler {
168+
return &tracedP2PServer{
169+
inner: inner,
170+
tracer: otel.Tracer("ev-node/p2p-service"),
171+
}
172+
}
173+
174+
func (t *tracedP2PServer) GetPeerInfo(
175+
ctx context.Context,
176+
req *connect.Request[emptypb.Empty],
177+
) (*connect.Response[pb.GetPeerInfoResponse], error) {
178+
ctx, span := t.tracer.Start(ctx, "P2PService.GetPeerInfo")
179+
defer span.End()
180+
181+
res, err := t.inner.GetPeerInfo(ctx, req)
182+
if err != nil {
183+
span.RecordError(err)
184+
span.SetStatus(codes.Error, err.Error())
185+
return nil, err
186+
}
187+
188+
span.SetAttributes(
189+
attribute.Int("peer_count", len(res.Msg.Peers)),
190+
)
191+
return res, nil
192+
}
193+
194+
func (t *tracedP2PServer) GetNetInfo(
195+
ctx context.Context,
196+
req *connect.Request[emptypb.Empty],
197+
) (*connect.Response[pb.GetNetInfoResponse], error) {
198+
ctx, span := t.tracer.Start(ctx, "P2PService.GetNetInfo")
199+
defer span.End()
200+
201+
res, err := t.inner.GetNetInfo(ctx, req)
202+
if err != nil {
203+
span.RecordError(err)
204+
span.SetStatus(codes.Error, err.Error())
205+
return nil, err
206+
}
207+
208+
if res.Msg.NetInfo != nil {
209+
span.SetAttributes(
210+
attribute.String("node_id", res.Msg.NetInfo.Id),
211+
attribute.Int("listen_address_count", len(res.Msg.NetInfo.ListenAddresses)),
212+
)
213+
}
214+
return res, nil
215+
}
216+
217+
// tracedConfigServer decorates a ConfigServiceHandler with OpenTelemetry spans.
218+
type tracedConfigServer struct {
219+
inner v1connect.ConfigServiceHandler
220+
tracer trace.Tracer
221+
}
222+
223+
// WithTracingConfigServer decorates the provided config service handler with tracing spans.
224+
func WithTracingConfigServer(inner v1connect.ConfigServiceHandler) v1connect.ConfigServiceHandler {
225+
return &tracedConfigServer{
226+
inner: inner,
227+
tracer: otel.Tracer("ev-node/config-service"),
228+
}
229+
}
230+
231+
func (t *tracedConfigServer) GetNamespace(
232+
ctx context.Context,
233+
req *connect.Request[emptypb.Empty],
234+
) (*connect.Response[pb.GetNamespaceResponse], error) {
235+
ctx, span := t.tracer.Start(ctx, "ConfigService.GetNamespace")
236+
defer span.End()
237+
238+
res, err := t.inner.GetNamespace(ctx, req)
239+
if err != nil {
240+
span.RecordError(err)
241+
span.SetStatus(codes.Error, err.Error())
242+
return nil, err
243+
}
244+
245+
span.SetAttributes(
246+
attribute.String("header_namespace", res.Msg.HeaderNamespace),
247+
attribute.String("data_namespace", res.Msg.DataNamespace),
248+
)
249+
return res, nil
250+
}
251+
252+
func (t *tracedConfigServer) GetSignerInfo(
253+
ctx context.Context,
254+
req *connect.Request[emptypb.Empty],
255+
) (*connect.Response[pb.GetSignerInfoResponse], error) {
256+
ctx, span := t.tracer.Start(ctx, "ConfigService.GetSignerInfo")
257+
defer span.End()
258+
259+
res, err := t.inner.GetSignerInfo(ctx, req)
260+
if err != nil {
261+
span.RecordError(err)
262+
span.SetStatus(codes.Error, err.Error())
263+
return nil, err
264+
}
265+
266+
span.SetAttributes(
267+
attribute.String("signer_address", hex.EncodeToString(res.Msg.Address)),
268+
)
269+
return res, nil
270+
}

0 commit comments

Comments
 (0)