diff --git a/clients/go/cmd/zbctl/internal/commands/root.go b/clients/go/cmd/zbctl/internal/commands/root.go index 447b23cd558a..e3a91caa15f8 100644 --- a/clients/go/cmd/zbctl/internal/commands/root.go +++ b/clients/go/cmd/zbctl/internal/commands/root.go @@ -131,6 +131,7 @@ var initClient = func(cmd *cobra.Command, args []string) error { client, err = zbc.NewClient(&zbc.ClientConfig{ GatewayAddress: fmt.Sprintf("%s:%s", host, port), CredentialsProvider: credsProvider, + UserAgent: "zeebe-client-zbctl/" + Version, }) return err } diff --git a/clients/go/pkg/zbc/client.go b/clients/go/pkg/zbc/client.go index c31af4219092..578f35ccb99b 100644 --- a/clients/go/pkg/zbc/client.go +++ b/clients/go/pkg/zbc/client.go @@ -65,7 +65,10 @@ type ClientConfig struct { // of 45 seconds being used KeepAlive time.Duration - DialOpts []grpc.DialOption + // UserAgent is an optional field, to specify the user-agent header which should be sent by each + // gRPC request. Defaults to zeebe-client-go/%version. + UserAgent string + DialOpts []grpc.DialOption } // ErrFileNotFound is returned whenever a file can't be found at the provided path. Use this value to do error comparison. @@ -158,7 +161,11 @@ func NewClient(config *ClientConfig) (Client, error) { return nil, err } - config.DialOpts = append(config.DialOpts, grpc.WithUserAgent("zeebe-client-go/"+getVersion())) + if config.UserAgent == "" { + config.UserAgent = "zeebe-client-go/" + getVersion() + } + + config.DialOpts = append(config.DialOpts, grpc.WithUserAgent(config.UserAgent)) conn, err := grpc.Dial(config.GatewayAddress, config.DialOpts...) if err != nil { diff --git a/clients/go/pkg/zbc/client_test.go b/clients/go/pkg/zbc/client_test.go index e58b2b05f14c..8bbda72930f3 100644 --- a/clients/go/pkg/zbc/client_test.go +++ b/clients/go/pkg/zbc/client_test.go @@ -18,6 +18,8 @@ import ( "context" "errors" "fmt" + "github.com/camunda/zeebe/clients/go/v8/internal/utils" + "google.golang.org/grpc/metadata" "net" "strconv" "strings" @@ -164,6 +166,61 @@ func (s *clientTestSuite) TestGatewayAddressEnvVar() { s.EqualValues(fmt.Sprintf("0.0.0.0:%s", parts[len(parts)-1]), config.GatewayAddress) } +func (s *clientTestSuite) TestDefaultUserAgent() { + // given + var incomingContext = make(map[string][]string) + lis, server := createServerWithUnaryInterceptor(func(ctx context.Context, _ interface{}, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) { + incomingContext, _ = metadata.FromIncomingContext(ctx) + return nil, nil + }) + go server.Serve(lis) + defer server.Stop() + + // when + client, err := NewClient(&ClientConfig{ + GatewayAddress: lis.Addr().String(), + UsePlaintextConnection: true, + }) + s.Require().NoError(err) + ctx, cancel := context.WithTimeout(context.Background(), utils.DefaultTestTimeout) + defer cancel() + + _, err = client.NewTopologyCommand().Send(ctx) + userAgent := incomingContext["user-agent"] + + // then + s.Require().Len(userAgent, 1) + s.Require().Contains(userAgent[0], "zeebe-client-go/"+getVersion()) +} + +func (s *clientTestSuite) TestSpecificUserAgent() { + // given + var incomingContext = make(map[string][]string) + lis, server := createServerWithUnaryInterceptor(func(ctx context.Context, _ interface{}, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) { + incomingContext, _ = metadata.FromIncomingContext(ctx) + return nil, nil + }) + go server.Serve(lis) + defer server.Stop() + + // when + client, err := NewClient(&ClientConfig{ + GatewayAddress: lis.Addr().String(), + UsePlaintextConnection: true, + UserAgent: "anotherUserAgentLikeZbctl", + }) + s.Require().NoError(err) + ctx, cancel := context.WithTimeout(context.Background(), utils.DefaultTestTimeout) + defer cancel() + + _, err = client.NewTopologyCommand().Send(ctx) + userAgent := incomingContext["user-agent"] + + // then + s.Require().Len(userAgent, 1) + s.Require().Contains(userAgent[0], "anotherUserAgentLikeZbctl") +} + func (s *clientTestSuite) TestCaCertificateEnvVar() { // given lis, grpcServer := createSecureServer(false)