Skip to content

Commit 83d991c

Browse files
committed
add support for tracing
1 parent 597c9a9 commit 83d991c

File tree

8 files changed

+154
-16
lines changed

8 files changed

+154
-16
lines changed

cmd/util/cmd/debug-script/cmd.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ func run(*cobra.Command, []string) {
127127
}
128128
}
129129

130-
debugger := debug.NewRemoteDebugger(chain, log.Logger)
130+
// TODO:
131+
const traceCadence = false
132+
debugger := debug.NewRemoteDebugger(chain, log.Logger, traceCadence)
131133

132134
// TODO: add support for arguments
133135
var arguments [][]byte

cmd/util/cmd/debug-tx/cmd.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,18 @@ import (
1313
"github.com/onflow/flow/protobuf/go/flow/executiondata"
1414
"github.com/rs/zerolog/log"
1515
"github.com/spf13/cobra"
16+
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
1617
"golang.org/x/exp/slices"
1718
"google.golang.org/grpc"
1819
"google.golang.org/grpc/credentials/insecure"
1920

2021
sdk "github.com/onflow/flow-go-sdk"
2122

23+
"github.com/onflow/flow-go/fvm"
2224
"github.com/onflow/flow-go/fvm/storage/snapshot"
2325
"github.com/onflow/flow-go/model/flow"
2426
"github.com/onflow/flow-go/module/grpcclient"
27+
"github.com/onflow/flow-go/module/trace"
2528
"github.com/onflow/flow-go/utils/debug"
2629
)
2730

@@ -36,6 +39,8 @@ var (
3639
flagProposalKeySeq uint64
3740
flagUseExecutionDataAPI bool
3841
flagDumpRegisters bool
42+
flagTracePath string
43+
flagTraceCadence bool
3944
)
4045

4146
var Cmd = &cobra.Command{
@@ -67,6 +72,10 @@ func init() {
6772
Cmd.Flags().BoolVar(&flagUseExecutionDataAPI, "use-execution-data-api", false, "use the execution data API")
6873

6974
Cmd.Flags().BoolVar(&flagDumpRegisters, "dump-registers", false, "dump registers")
75+
76+
Cmd.Flags().StringVar(&flagTracePath, "trace", "", "enable tracing to given path")
77+
78+
Cmd.Flags().BoolVar(&flagTraceCadence, "trace-cadence", false, "trace Cadence")
7079
}
7180

7281
func run(_ *cobra.Command, args []string) {
@@ -178,7 +187,55 @@ func runTransactionID(txID flow.Identifier, flowClient *client.Client, chain flo
178187

179188
blockSnapshot := newBlockSnapshot(remoteSnapshot)
180189

181-
debugger := debug.NewRemoteDebugger(chain, log.Logger)
190+
var fvmOptions []fvm.Option
191+
192+
if flagTracePath != "" {
193+
194+
var traceFile *os.File
195+
if flagTracePath == "-" {
196+
traceFile = os.Stdout
197+
} else {
198+
traceFile, err = os.Create(flagTracePath)
199+
if err != nil {
200+
log.Fatal().Err(err).Msg("failed to create trace file")
201+
}
202+
defer traceFile.Close()
203+
}
204+
205+
exporter, err := stdouttrace.New(
206+
stdouttrace.WithWriter(traceFile),
207+
)
208+
if err != nil {
209+
log.Fatal().Err(err).Msg("failed to create trace exporter")
210+
}
211+
212+
tracer, err := trace.NewTracerWithExporter(
213+
log.Logger,
214+
"debug-tx",
215+
flagChain,
216+
trace.SensitivityCaptureAll,
217+
exporter,
218+
)
219+
if err != nil {
220+
log.Fatal().Err(err).Msg("failed to create tracer")
221+
}
222+
223+
span, _ := tracer.StartTransactionSpan(context.TODO(), txID, "")
224+
defer span.End()
225+
226+
fvmOptions = append(
227+
fvmOptions,
228+
fvm.WithTracer(tracer),
229+
fvm.WithSpan(span),
230+
)
231+
}
232+
233+
debugger := debug.NewRemoteDebugger(
234+
chain,
235+
log.Logger,
236+
flagTraceCadence,
237+
fvmOptions...,
238+
)
182239

183240
for _, blockTx := range txsResult {
184241
blockTxID := flow.Identifier(blockTx.ID())

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ require (
112112
github.com/onflow/wal v1.0.2
113113
github.com/slok/go-http-metrics v0.12.0
114114
github.com/sony/gobreaker v0.5.0
115+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0
115116
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da
116117
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a
117118
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 h1:FFeLy
13541354
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0/go.mod h1:TMu73/k1CP8nBUpDLc71Wj/Kf7ZS9FK5b53VapRsP9o=
13551355
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc=
13561356
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I=
1357+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec=
1358+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E=
13571359
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
13581360
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
13591361
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=

module/trace/noop.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ func (t *NoopTracer) StartCollectionSpan(
6363
return NoopSpan, ctx
6464
}
6565

66+
func (t *NoopTracer) StartTransactionSpan(
67+
ctx context.Context,
68+
entityID flow.Identifier,
69+
spanName SpanName,
70+
opts ...trace.SpanStartOption,
71+
) (
72+
trace.Span,
73+
context.Context,
74+
) {
75+
return NoopSpan, ctx
76+
}
77+
6678
func (t *NoopTracer) StartSpanFromContext(
6779
ctx context.Context,
6880
operationName SpanName,

module/trace/trace.go

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,36 @@ func NewTracer(
5555
) (
5656
*Tracer,
5757
error,
58+
) {
59+
ctx := context.TODO()
60+
// OLTP trace gRPC client initialization. Connection parameters for the exporter are extracted
61+
// from environment variables. e.g.: `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`.
62+
//
63+
// For more information, see OpenTelemetry specification:
64+
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/protocol/exporter.md
65+
traceExporter, err := otlptracegrpc.New(ctx)
66+
if err != nil {
67+
return nil, fmt.Errorf("failed to create trace exporter: %w", err)
68+
}
69+
70+
return NewTracerWithExporter(
71+
log,
72+
serviceName,
73+
chainID,
74+
sensitivity,
75+
traceExporter,
76+
)
77+
}
78+
79+
func NewTracerWithExporter(
80+
log zerolog.Logger,
81+
serviceName string,
82+
chainID string,
83+
sensitivity uint,
84+
traceExporter sdktrace.SpanExporter,
85+
) (
86+
*Tracer,
87+
error,
5888
) {
5989
ctx := context.TODO()
6090
res, err := resource.New(
@@ -68,16 +98,6 @@ func NewTracer(
6898
return nil, fmt.Errorf("failed to create resource: %w", err)
6999
}
70100

71-
// OLTP trace gRPC client initialization. Connection parameters for the exporter are extracted
72-
// from environment variables. e.g.: `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`.
73-
//
74-
// For more information, see OpenTelemetry specification:
75-
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.12.0/specification/protocol/exporter.md
76-
traceExporter, err := otlptracegrpc.New(ctx)
77-
if err != nil {
78-
return nil, fmt.Errorf("failed to create trace exporter: %w", err)
79-
}
80-
81101
tracerProvider := sdktrace.NewTracerProvider(
82102
sdktrace.WithResource(res),
83103
sdktrace.WithBatcher(traceExporter),
@@ -207,6 +227,18 @@ func (t *Tracer) StartCollectionSpan(
207227
return t.startEntitySpan(ctx, collectionID, EntityTypeCollection, spanName, opts...)
208228
}
209229

230+
func (t *Tracer) StartTransactionSpan(
231+
ctx context.Context,
232+
transactionID flow.Identifier,
233+
spanName SpanName,
234+
opts ...trace.SpanStartOption,
235+
) (
236+
trace.Span,
237+
context.Context,
238+
) {
239+
return t.startEntitySpan(ctx, transactionID, EntityTypeTransaction, spanName, opts...)
240+
}
241+
210242
func (t *Tracer) StartSpanFromContext(
211243
ctx context.Context,
212244
operationName SpanName,

module/tracer.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type Tracer interface {
3535
context.Context,
3636
)
3737

38-
// StartCollectionSpan starts an span for a collection, built as a child of
38+
// StartCollectionSpan starts a span for a collection, built as a child of
3939
// rootSpan. It also returns the context including this span which can be
4040
// used for nested calls.
4141
StartCollectionSpan(
@@ -48,6 +48,16 @@ type Tracer interface {
4848
context.Context,
4949
)
5050

51+
StartTransactionSpan(
52+
ctx context.Context,
53+
transactionID flow.Identifier,
54+
spanName trace.SpanName,
55+
opts ...otelTrace.SpanStartOption,
56+
) (
57+
otelTrace.Span,
58+
context.Context,
59+
)
60+
5161
StartSpanFromContext(
5262
ctx context.Context,
5363
operationName trace.SpanName,

utils/debug/remoteDebugger.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package debug
22

33
import (
44
"github.com/onflow/cadence"
5+
"github.com/onflow/cadence/runtime"
56
"github.com/rs/zerolog"
67

78
"github.com/onflow/flow-go/fvm"
9+
reusableRuntime "github.com/onflow/flow-go/fvm/runtime"
810
"github.com/onflow/flow-go/fvm/storage/snapshot"
911
"github.com/onflow/flow-go/model/flow"
1012
)
@@ -14,22 +16,42 @@ type RemoteDebugger struct {
1416
ctx fvm.Context
1517
}
1618

19+
// ReusableCadenceRuntimePoolSize is the size of the reusable cadence runtime pool.
20+
// Copied from engine/execution/computation/manager.go to avoid circular dependency.
21+
const reusableCadenceRuntimePoolSize = 1000
22+
1723
// NewRemoteDebugger creates a new remote debugger.
1824
// NOTE: Make sure to use the same version of flow-go as the network
1925
// you are collecting registers from, otherwise the execution might differ
2026
// from the way it runs on the network
2127
func NewRemoteDebugger(
2228
chain flow.Chain,
2329
logger zerolog.Logger,
30+
traceCadence bool,
31+
options ...fvm.Option,
2432
) *RemoteDebugger {
2533
vm := fvm.NewVirtualMachine()
2634

2735
// no signature processor here
2836
// TODO Maybe we add fee-deduction step as well
37+
2938
ctx := fvm.NewContext(
30-
fvm.WithLogger(logger),
31-
fvm.WithChain(chain),
32-
fvm.WithAuthorizationChecksEnabled(false),
39+
append(
40+
[]fvm.Option{
41+
fvm.WithLogger(logger),
42+
fvm.WithChain(chain),
43+
fvm.WithAuthorizationChecksEnabled(false),
44+
fvm.WithReusableCadenceRuntimePool(
45+
reusableRuntime.NewReusableCadenceRuntimePool(
46+
reusableCadenceRuntimePoolSize,
47+
runtime.Config{
48+
TracingEnabled: traceCadence,
49+
},
50+
)),
51+
fvm.WithEVMEnabled(true),
52+
},
53+
options...,
54+
)...,
3355
)
3456

3557
return &RemoteDebugger{

0 commit comments

Comments
 (0)