diff --git a/cmd/frostfs-cli/internal/client/sdk.go b/cmd/frostfs-cli/internal/client/sdk.go index 13dacc04cd..79d3dcb0d3 100644 --- a/cmd/frostfs-cli/internal/client/sdk.go +++ b/cmd/frostfs-cli/internal/client/sdk.go @@ -12,9 +12,11 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network" + tracing "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing/grpc" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client" "github.com/spf13/cobra" "github.com/spf13/viper" + "google.golang.org/grpc" ) var errInvalidEndpoint = errors.New("provided RPC endpoint is incorrect") @@ -59,6 +61,9 @@ func GetSDKClient(ctx context.Context, cmd *cobra.Command, key *ecdsa.PrivateKey common.PrintVerbose(cmd, "Set request timeout to %s.", timeout) } + prmDial.SetGRPCDialOptions( + grpc.WithChainUnaryInterceptor(tracing.NewUnaryClientInteceptor()), + grpc.WithChainStreamInterceptor(tracing.NewStreamClientInterceptor())) c.Init(prmInit) diff --git a/cmd/frostfs-cli/internal/common/tracing.go b/cmd/frostfs-cli/internal/common/tracing.go new file mode 100644 index 0000000000..7a96846671 --- /dev/null +++ b/cmd/frostfs-cli/internal/common/tracing.go @@ -0,0 +1,64 @@ +package common + +import ( + "context" + "fmt" + "sort" + "strings" + + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" + commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" + "git.frostfs.info/TrueCloudLab/frostfs-node/misc" + "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing" + "github.com/spf13/cobra" + "go.opentelemetry.io/otel/trace" +) + +type spanKey struct{} + +// StopClientCommandSpan stops tracing span for the command and prints trace ID on the standard output. +func StopClientCommandSpan(cmd *cobra.Command, _ []string) { + span, ok := cmd.Context().Value(spanKey{}).(trace.Span) + if !ok { + return + } + + span.End() + + // Noop provider cannot fail on flush. + _ = tracing.Shutdown(cmd.Context()) + + cmd.PrintErrf("Trace ID: %s\n", span.SpanContext().TraceID()) +} + +// StartClientCommandSpan starts tracing span for the command. +func StartClientCommandSpan(cmd *cobra.Command) { + enableTracing, err := cmd.Flags().GetBool(commonflags.TracingFlag) + if err != nil || !enableTracing { + return + } + + _, err = tracing.Setup(cmd.Context(), tracing.Config{ + Enabled: true, + Exporter: tracing.NoOpExporter, + Service: "frostfs-cli", + Version: misc.Version, + }) + commonCmd.ExitOnErr(cmd, "init tracing: %w", err) + + var components sort.StringSlice + for c := cmd; c != nil; c = c.Parent() { + fmt.Println(c.Name()) + components = append(components, c.Name()) + } + for i, j := 0, len(components)-1; i < j; { + components.Swap(i, j) + i++ + j-- + } + + operation := strings.Join(components, ".") + ctx, span := tracing.StartSpanFromContext(cmd.Context(), operation) + ctx = context.WithValue(ctx, spanKey{}, span) + cmd.SetContext(ctx) +} diff --git a/cmd/frostfs-cli/internal/commonflags/flags.go b/cmd/frostfs-cli/internal/commonflags/flags.go index 810e621072..5049dc3b15 100644 --- a/cmd/frostfs-cli/internal/commonflags/flags.go +++ b/cmd/frostfs-cli/internal/commonflags/flags.go @@ -47,6 +47,9 @@ const ( OIDFlag = "oid" OIDFlagUsage = "Object ID." + + TracingFlag = "trace" + TracingFlagUsage = "Generate trace ID and print it." ) // Init adds common flags to the command: @@ -54,12 +57,14 @@ const ( // - WalletPath, // - Account, // - RPC, +// - Tracing, // - Timeout. func Init(cmd *cobra.Command) { InitWithoutRPC(cmd) ff := cmd.Flags() ff.StringP(RPC, RPCShorthand, RPCDefault, RPCUsage) + ff.Bool(TracingFlag, false, TracingFlagUsage) ff.DurationP(Timeout, TimeoutShorthand, TimeoutDefault, TimeoutUsage) } diff --git a/cmd/frostfs-cli/modules/accounting/root.go b/cmd/frostfs-cli/modules/accounting/root.go index 8ab8aa1255..f94488b6f7 100644 --- a/cmd/frostfs-cli/modules/accounting/root.go +++ b/cmd/frostfs-cli/modules/accounting/root.go @@ -1,6 +1,7 @@ package accounting import ( + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -17,7 +18,9 @@ var Cmd = &cobra.Command{ _ = viper.BindPFlag(commonflags.WalletPath, flags.Lookup(commonflags.WalletPath)) _ = viper.BindPFlag(commonflags.Account, flags.Lookup(commonflags.Account)) _ = viper.BindPFlag(commonflags.RPC, flags.Lookup(commonflags.RPC)) + common.StartClientCommandSpan(cmd) }, + PersistentPostRun: common.StopClientCommandSpan, } func init() { diff --git a/cmd/frostfs-cli/modules/container/create.go b/cmd/frostfs-cli/modules/container/create.go index 2acdfc16fa..e5bbeacd46 100644 --- a/cmd/frostfs-cli/modules/container/create.go +++ b/cmd/frostfs-cli/modules/container/create.go @@ -141,6 +141,7 @@ func initContainerCreateCmd() { // Init common flags flags.StringP(commonflags.RPC, commonflags.RPCShorthand, commonflags.RPCDefault, commonflags.RPCUsage) + flags.Bool(commonflags.TracingFlag, false, commonflags.TracingFlagUsage) flags.DurationP(commonflags.Timeout, commonflags.TimeoutShorthand, commonflags.TimeoutDefault, commonflags.TimeoutUsage) flags.StringP(commonflags.WalletPath, commonflags.WalletPathShorthand, commonflags.WalletPathDefault, commonflags.WalletPathUsage) flags.StringP(commonflags.Account, commonflags.AccountShorthand, commonflags.AccountDefault, commonflags.AccountUsage) diff --git a/cmd/frostfs-cli/modules/container/delete.go b/cmd/frostfs-cli/modules/container/delete.go index 54b49a32d7..f5b69edfdc 100644 --- a/cmd/frostfs-cli/modules/container/delete.go +++ b/cmd/frostfs-cli/modules/container/delete.go @@ -124,6 +124,7 @@ func initContainerDeleteCmd() { flags.StringP(commonflags.WalletPath, commonflags.WalletPathShorthand, commonflags.WalletPathDefault, commonflags.WalletPathUsage) flags.StringP(commonflags.Account, commonflags.AccountShorthand, commonflags.AccountDefault, commonflags.AccountUsage) flags.StringP(commonflags.RPC, commonflags.RPCShorthand, commonflags.RPCDefault, commonflags.RPCUsage) + flags.Bool(commonflags.TracingFlag, false, commonflags.TracingFlagUsage) flags.StringVar(&containerID, commonflags.CIDFlag, "", commonflags.CIDFlagUsage) flags.BoolVar(&containerAwait, "await", false, "Block execution until container is removed") diff --git a/cmd/frostfs-cli/modules/container/root.go b/cmd/frostfs-cli/modules/container/root.go index ab7f5fb908..f3c3e0e3a0 100644 --- a/cmd/frostfs-cli/modules/container/root.go +++ b/cmd/frostfs-cli/modules/container/root.go @@ -1,6 +1,7 @@ package container import ( + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" "github.com/spf13/cobra" ) @@ -15,7 +16,9 @@ var Cmd = &cobra.Command{ // the viper before execution commonflags.Bind(cmd) commonflags.BindAPI(cmd) + common.StartClientCommandSpan(cmd) }, + PersistentPostRun: common.StopClientCommandSpan, } func init() { diff --git a/cmd/frostfs-cli/modules/netmap/root.go b/cmd/frostfs-cli/modules/netmap/root.go index aaa83f12fc..006ac6d9f3 100644 --- a/cmd/frostfs-cli/modules/netmap/root.go +++ b/cmd/frostfs-cli/modules/netmap/root.go @@ -1,6 +1,7 @@ package netmap import ( + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" "github.com/spf13/cobra" ) @@ -14,7 +15,9 @@ var Cmd = &cobra.Command{ // the viper before execution commonflags.Bind(cmd) commonflags.BindAPI(cmd) + common.StartClientCommandSpan(cmd) }, + PersistentPostRun: common.StopClientCommandSpan, } func init() { diff --git a/cmd/frostfs-cli/modules/object/root.go b/cmd/frostfs-cli/modules/object/root.go index 8861530757..23badc5766 100644 --- a/cmd/frostfs-cli/modules/object/root.go +++ b/cmd/frostfs-cli/modules/object/root.go @@ -1,6 +1,7 @@ package object import ( + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" "github.com/spf13/cobra" ) @@ -15,7 +16,9 @@ var Cmd = &cobra.Command{ // the viper before execution commonflags.Bind(cmd) commonflags.BindAPI(cmd) + common.StartClientCommandSpan(cmd) }, + PersistentPostRun: common.StopClientCommandSpan, } func init() { diff --git a/cmd/frostfs-cli/modules/session/create.go b/cmd/frostfs-cli/modules/session/create.go index 0cc12606ef..53f6e8bc49 100644 --- a/cmd/frostfs-cli/modules/session/create.go +++ b/cmd/frostfs-cli/modules/session/create.go @@ -6,6 +6,7 @@ import ( "os" internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client" + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key" commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common" @@ -29,10 +30,12 @@ var createCmd = &cobra.Command{ Use: "create", Short: "Create session token", Run: createSession, - PersistentPreRun: func(cmd *cobra.Command, _ []string) { + PersistentPreRun: func(cmd *cobra.Command, args []string) { _ = viper.BindPFlag(commonflags.WalletPath, cmd.Flags().Lookup(commonflags.WalletPath)) _ = viper.BindPFlag(commonflags.Account, cmd.Flags().Lookup(commonflags.Account)) + common.StartClientCommandSpan(cmd) }, + PersistentPostRun: common.StopClientCommandSpan, } func init() {