From c9b7602fec5fdd12f2e397ec3b100dae2b5455ef Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Sun, 21 Jul 2024 17:59:51 +0530 Subject: [PATCH 1/9] feat: implements nats subject change, to solve nats storage and performance issues --- apps/console/internal/app/app.go | 4 +- .../internal/app/adapter-resource-apply.go | 4 +- apps/infra/internal/app/app.go | 5 +- .../internal/app/grpc-server.go | 302 ++++++++---------- common/kafka-topic-name.go | 61 +++- pkg/functions/main.go | 8 + pkg/logging/slog-logger.go | 33 ++ 7 files changed, 235 insertions(+), 182 deletions(-) create mode 100644 pkg/logging/slog-logger.go diff --git a/apps/console/internal/app/app.go b/apps/console/internal/app/app.go index 86f0cb900..7c01f75d2 100644 --- a/apps/console/internal/app/app.go +++ b/apps/console/internal/app/app.go @@ -164,7 +164,7 @@ var Module = fx.Module("app", }), fx.Provide(func(jc *nats.JetstreamClient, ev *env.Env, logger logging.Logger) (ErrorOnApplyConsumer, error) { - topic := common.GetPlatformClusterMessagingTopic("*", "*", common.ConsoleReceiver, common.EventErrorOnApply) + topic := common.ReceiveFromAgentSubjectName(common.ReceiveFromAgentArgs{AccountName: "*", ClusterName: "*"}, common.ConsoleReceiver, common.EventErrorOnApply) consumerName := "console:error-on-apply" return msg_nats.NewJetstreamConsumer(context.TODO(), jc, msg_nats.JetstreamConsumerArgs{ Stream: ev.NatsResourceSyncStream, @@ -190,7 +190,7 @@ var Module = fx.Module("app", }), fx.Provide(func(jc *nats.JetstreamClient, ev *env.Env, logger logging.Logger) (ResourceUpdateConsumer, error) { - topic := common.GetPlatformClusterMessagingTopic("*", "*", common.ConsoleReceiver, common.EventResourceUpdate) + topic := common.ReceiveFromAgentSubjectName(common.ReceiveFromAgentArgs{AccountName: "*", ClusterName: "*"}, common.ConsoleReceiver, common.EventResourceUpdate) consumerName := "console:resource-updates" return msg_nats.NewJetstreamConsumer(context.TODO(), jc, msg_nats.JetstreamConsumerArgs{ diff --git a/apps/infra/internal/app/adapter-resource-apply.go b/apps/infra/internal/app/adapter-resource-apply.go index d4e3bcd8d..228cb632a 100644 --- a/apps/infra/internal/app/adapter-resource-apply.go +++ b/apps/infra/internal/app/adapter-resource-apply.go @@ -51,7 +51,7 @@ func (a *resourceDispatcherImpl) ApplyToTargetCluster(ctx domain.InfraContext, c } err = a.producer.Produce(ctx, msgTypes.ProduceMsg{ - Subject: common.GetTenantClusterMessagingTopic(ctx.AccountName, clusterName), + Subject: common.SendToAgentSubjectName(ctx.AccountName, clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()), Payload: b, }) @@ -75,7 +75,7 @@ func (d *resourceDispatcherImpl) DeleteFromTargetCluster(ctx domain.InfraContext } err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ - Subject: common.GetTenantClusterMessagingTopic(ctx.AccountName, clusterName), + Subject: common.SendToAgentSubjectName(ctx.AccountName, clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()), Payload: b, }) diff --git a/apps/infra/internal/app/app.go b/apps/infra/internal/app/app.go index 7f83ebedc..6aa372f7a 100644 --- a/apps/infra/internal/app/app.go +++ b/apps/infra/internal/app/app.go @@ -2,6 +2,7 @@ package app import ( "context" + "github.com/kloudlite/api/grpc-interfaces/kloudlite.io/rpc/console" "github.com/kloudlite/api/apps/infra/internal/entities" @@ -121,7 +122,7 @@ var Module = fx.Module( }), fx.Provide(func(jsc *nats.JetstreamClient, ev *env.Env) (ReceiveResourceUpdatesConsumer, error) { - topic := common.GetPlatformClusterMessagingTopic("*", "*", common.InfraReceiver, common.EventResourceUpdate) + topic := common.ReceiveFromAgentSubjectName(common.ReceiveFromAgentArgs{AccountName: "*", ClusterName: "*"}, common.InfraReceiver, common.EventResourceUpdate) consumerName := "infra:resource-updates" return msg_nats.NewJetstreamConsumer(context.TODO(), jsc, msg_nats.JetstreamConsumerArgs{ @@ -148,7 +149,7 @@ var Module = fx.Module( }), fx.Provide(func(jsc *nats.JetstreamClient, ev *env.Env) (ErrorOnApplyConsumer, error) { - topic := common.GetPlatformClusterMessagingTopic("*", "*", common.ConsoleReceiver, common.EventErrorOnApply) + topic := common.ReceiveFromAgentSubjectName(common.ReceiveFromAgentArgs{AccountName: "*", ClusterName: "*"}, common.InfraReceiver, common.EventErrorOnApply) consumerName := "infra:error-on-apply" diff --git a/apps/message-office/internal/app/grpc-server.go b/apps/message-office/internal/app/grpc-server.go index 6ab512a08..967a712f9 100644 --- a/apps/message-office/internal/app/grpc-server.go +++ b/apps/message-office/internal/app/grpc-server.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "encoding/base64" "fmt" + "log/slog" "strings" "time" @@ -27,7 +28,6 @@ import ( "github.com/kloudlite/api/apps/message-office/internal/domain" "github.com/kloudlite/api/apps/message-office/internal/env" fn "github.com/kloudlite/api/pkg/functions" - "github.com/kloudlite/api/pkg/logging" ) type ( @@ -36,7 +36,7 @@ type ( grpcServer struct { messages.UnimplementedMessageDispatchServiceServer - logger logging.Logger + logger *slog.Logger infraClient infra.InfraClient @@ -47,28 +47,36 @@ type ( domain domain.Domain createConsumer func(ctx context.Context, accountName string, clusterName string) (messaging.Consumer, error) - - resourceUpdatesCounter int64 - infraUpdatesCounter int64 - crUpdatesCounter int64 - errorMessagesCounter int64 - clusterUpdatesCounter int64 } ) // ReceiveConsoleResourceUpdate implements messages.MessageDispatchServiceServer. -func (g *grpcServer) ReceiveConsoleResourceUpdate(ctx context.Context, msg *messages.ResourceUpdate) (*messages.Empty, error) { +func (g *grpcServer) ReceiveConsoleResourceUpdate(ctx context.Context, msg *messages.ResourceUpdate) (_ *messages.Empty, err error) { accountName, clusterName, err := g.validateAndDecodeFromGrpcContext(ctx, g.ev.TokenHashingSecret) if err != nil { return nil, err } - logger := g.logger.WithKV("accountName", accountName).WithKV("cluster", clusterName) - logger.Debugf("console resource update request received") + + start := time.Now() + logger := g.logger.With("accountName", accountName, "cluster", "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), clusterName, "for", common.ConsoleReceiver, "request-id", fn.UUID()) + logger.Debug("RECEIVED resource update") defer func() { - logger.Debugf("console resource update request processed") + if err != nil { + logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) + return + } + + logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) }() - if err := g.processConsoleResourceUpdate(ctx, accountName, clusterName, msg); err != nil { + if err := dispatchResourceUpdate(ctx, common.ConsoleReceiver, ResourceUpdateArgs{ + logger: logger, + updatesProducer: g.updatesProducer, + + AccountName: accountName, + ClusterName: clusterName, + Message: msg, + }); err != nil { return nil, err } @@ -76,19 +84,31 @@ func (g *grpcServer) ReceiveConsoleResourceUpdate(ctx context.Context, msg *mess } // ReceiveContainerRegistryUpdate implements messages.MessageDispatchServiceServer. -func (g *grpcServer) ReceiveContainerRegistryUpdate(ctx context.Context, msg *messages.ResourceUpdate) (*messages.Empty, error) { +func (g *grpcServer) ReceiveContainerRegistryUpdate(ctx context.Context, msg *messages.ResourceUpdate) (_ *messages.Empty, err error) { accountName, clusterName, err := g.validateAndDecodeFromGrpcContext(ctx, g.ev.TokenHashingSecret) if err != nil { return nil, err } - logger := g.logger.WithKV("accountName", accountName).WithKV("cluster", clusterName) - logger.Debugf("container registry resource update request received") + start := time.Now() + logger := g.logger.With("accountName", accountName, "cluster", "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), clusterName, "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) + logger.Debug("RECEIVED resource update") defer func() { - logger.Debugf("container registry resource update request processed") + if err != nil { + logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) + return + } + logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) }() - if err := g.processContainerRegistryResourceUpdate(ctx, accountName, clusterName, msg); err != nil { + if err := dispatchResourceUpdate(ctx, common.ContainerRegistryReceiver, ResourceUpdateArgs{ + logger: logger, + updatesProducer: g.updatesProducer, + + AccountName: accountName, + ClusterName: clusterName, + Message: msg, + }); err != nil { return nil, err } @@ -102,15 +122,25 @@ func (g *grpcServer) ReceiveError(ctx context.Context, msg *messages.ErrorData) return nil, err } - logger := g.logger.WithKV("accountName", accountName).WithKV("cluster", clusterName) - logger.Debugf("request received for access token validation") - isValid := true - + start := time.Now() + logger := g.logger.With("accountName", accountName, "cluster", "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), clusterName, "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) + logger.Debug("RECEIVED error-on-apply update") defer func() { - logger.Debugf("is access token valid? (%v)", isValid) + if err != nil { + logger.Error("FAILED error-on-apply update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) + return + } + logger.Info("DISPATCHED error-on-apply update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) }() - if err := g.processError(ctx, accountName, clusterName, msg.Message); err != nil { + if err := processError(ctx, ProcessErrorArgs{ + logger: logger, + updatesProducer: g.updatesProducer, + + AccountName: accountName, + ClusterName: clusterName, + Error: msg, + }); err != nil { return nil, err } @@ -118,29 +148,37 @@ func (g *grpcServer) ReceiveError(ctx context.Context, msg *messages.ErrorData) } // ReceiveInfraResourceUpdate implements messages.MessageDispatchServiceServer. -func (g *grpcServer) ReceiveInfraResourceUpdate(ctx context.Context, msg *messages.ResourceUpdate) (*messages.Empty, error) { +func (g *grpcServer) ReceiveInfraResourceUpdate(ctx context.Context, msg *messages.ResourceUpdate) (_ *messages.Empty, err error) { accountName, clusterName, err := g.validateAndDecodeFromGrpcContext(ctx, g.ev.TokenHashingSecret) if err != nil { return nil, err } - logger := g.logger.WithKV("accountName", accountName).WithKV("cluster", clusterName) - logger.Debugf("infra resource update request received") + start := time.Now() + logger := g.logger.With("accountName", accountName, "cluster", "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), clusterName, "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) + logger.Debug("RECEIVED resource update") defer func() { - logger.Debugf("infra resource update request processed") + if err != nil { + logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) + return + } + logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) }() - if err := g.processInfraResourceUpdate(ctx, accountName, clusterName, msg); err != nil { + if err := dispatchResourceUpdate(ctx, common.InfraReceiver, ResourceUpdateArgs{ + logger: logger, + updatesProducer: g.updatesProducer, + + AccountName: accountName, + ClusterName: clusterName, + Message: msg, + }); err != nil { return nil, err } return &messages.Empty{}, nil } -// ReceiveError implements messages.MessageDispatchServiceServer. -// func (g *grpcServer) ReceiveError(ctx context.Context, msg *messages.ErrorData) (*messages.Empty, error) { -// } - // Ping implements messages.MessageDispatchServiceServer. func (*grpcServer) Ping(context.Context, *messages.Empty) (*messages.PingOutput, error) { return &messages.PingOutput{Ok: true}, nil @@ -246,58 +284,62 @@ func (g *grpcServer) ValidateAccessToken(ctx context.Context, msg *messages.Vali return nil, err } - g.logger.WithKV("account", accountName).WithKV("cluster", clusterName).Infof("validated access token") + g.logger.With("account", accountName).With("cluster", clusterName).Info("validated access token") return &messages.ValidateAccessTokenOut{Valid: true}, nil } -func (g *grpcServer) processError(ctx context.Context, accountName string, clusterName string, msg []byte) (err error) { - g.errorMessagesCounter++ - logger := g.logger.WithKV("accountName", accountName).WithKV("cluster", clusterName) +type ProcessErrorArgs struct { + logger *slog.Logger + updatesProducer UpdatesProducer - logger.Infof("[%v] received error-on-apply message", g.errorMessagesCounter) - defer func() { - if err != nil { - err = errors.Wrap(err, fmt.Sprintf("[%v] (with ERROR) processed error-on-apply message", g.clusterUpdatesCounter)) - logger.Errorf(err) - return - } - logger.Infof("[%v] processed error-on-apply message", g.infraUpdatesCounter) - }() + AccountName string + ClusterName string + Error *messages.ErrorData +} +func processError(ctx context.Context, args ProcessErrorArgs) (err error) { b, err := msgOfficeT.MarshalErrMessage(msgOfficeT.ErrMessage{ - AccountName: accountName, - ClusterName: clusterName, - Error: msg, + AccountName: args.AccountName, + ClusterName: args.ClusterName, + Error: args.Error.Message, }) if err != nil { - return errors.Wrap(err, "while marshaling resource update") + return errors.Wrap(err, "marshaling resource update") + } + + subjectParams := common.ReceiveFromAgentArgs{ + AccountName: args.AccountName, + ClusterName: args.ClusterName, + GVK: args.Error.Gvk, + Namespace: args.Error.Namespace, + Name: args.Error.Name, } - msgTopic := common.GetPlatformClusterMessagingTopic(accountName, clusterName, common.InfraReceiver, common.EventErrorOnApply) - if err := g.updatesProducer.Produce(ctx, types.ProduceMsg{Subject: msgTopic, Payload: b}); err != nil { + msgTopic := common.ReceiveFromAgentSubjectName(subjectParams, common.InfraReceiver, common.EventErrorOnApply) + if err := args.updatesProducer.Produce(ctx, types.ProduceMsg{Subject: msgTopic, Payload: b}); err != nil { return errors.Wrap(err, fmt.Sprintf("while producing to topic (%s)", msgTopic)) } - logger.Infof("[%v] dispatched error-on-apply message to %s receiver", g.errorMessagesCounter, common.InfraReceiver) + args.logger.Debug("dispatched error-on-apply message", "subject", msgTopic, "to", common.InfraReceiver) - msgTopic = common.GetPlatformClusterMessagingTopic(accountName, clusterName, common.ConsoleReceiver, common.EventErrorOnApply) - if err := g.updatesProducer.Produce(ctx, types.ProduceMsg{Subject: msgTopic, Payload: b}); err != nil { + msgTopic = common.ReceiveFromAgentSubjectName(subjectParams, common.ConsoleReceiver, common.EventErrorOnApply) + if err := args.updatesProducer.Produce(ctx, types.ProduceMsg{Subject: msgTopic, Payload: b}); err != nil { return errors.Wrap(err, fmt.Sprintf("while producing to topic (%s)", msgTopic)) } - logger.Infof("[%v] dispatched error-on-apply message to %s receiver", g.errorMessagesCounter, common.ConsoleReceiver) + args.logger.Debug("dispatched error-on-apply message", "subject", msgTopic, "to", common.ConsoleReceiver) - msgTopic = common.GetPlatformClusterMessagingTopic(accountName, clusterName, common.ContainerRegistryReceiver, common.EventErrorOnApply) - if err := g.updatesProducer.Produce(ctx, types.ProduceMsg{Subject: msgTopic, Payload: b}); err != nil { + msgTopic = common.ReceiveFromAgentSubjectName(subjectParams, common.ContainerRegistryReceiver, common.EventErrorOnApply) + if err := args.updatesProducer.Produce(ctx, types.ProduceMsg{Subject: msgTopic, Payload: b}); err != nil { return errors.Wrap(err, fmt.Sprintf("while producing to topic (%s)", msgTopic)) } - logger.Infof("[%v] dispatched error-on-apply message to %s receiver", g.errorMessagesCounter, common.ContainerRegistryReceiver) + args.logger.Debug("dispatched error-on-apply message", "subject", msgTopic, "to", common.ContainerRegistryReceiver) return nil } // GetAccessToken implements messages.MessageDispatchServiceServer func (g *grpcServer) GetAccessToken(ctx context.Context, msg *messages.GetAccessTokenIn) (*messages.GetAccessTokenOut, error) { - g.logger.Infof("request received for cluster-token (%q) exchange", msg.ClusterToken) + g.logger.Info("request received for cluster-token (%q) exchange", msg.ClusterToken) ct, err := g.domain.FindClusterToken(ctx, msg.ClusterToken) if err != nil { @@ -308,7 +350,7 @@ func (g *grpcServer) GetAccessToken(ctx context.Context, msg *messages.GetAccess } s := encodeAccessToken(ct.AccountName, ct.ClusterName, msg.ClusterToken, g.ev.TokenHashingSecret) - g.logger.Infof("SUCCESSFUL cluster-token exchange for account=%q, cluster=%q", ct.AccountName, ct.ClusterName) + g.logger.Info("SUCCESSFUL cluster-token exchange for account=%q, cluster=%q", ct.AccountName, ct.ClusterName) return &messages.GetAccessTokenOut{ ProtocolVersion: g.ev.GrpcMessageProtocolVersion, @@ -324,10 +366,10 @@ func (g *grpcServer) SendActions(request *messages.Empty, server messages.Messag return klErrors.NewE(err) } - logger := g.logger.WithKV("accountName", accountName, "clusterName", clusterName) - logger.Infof("request received for sending actions to cluster") + logger := g.logger.With("accountName", accountName, "clusterName", clusterName) + logger.Info("request received for sending actions to cluster") defer func() { - logger.Infof("stopped sending actions to cluster") + logger.Info("stopped sending actions to cluster") }() key := fmt.Sprintf("%s/%s", accountName, clusterName) @@ -338,151 +380,86 @@ func (g *grpcServer) SendActions(request *messages.Empty, server messages.Messag } // TODO: implement cluster online feature, so that we can mark the cluster as online/offline - logger.Infof("consumer is available now") + logger.Info("consumer is available now") if _, err := g.infraClient.MarkClusterOnlineAt(server.Context(), &infra.MarkClusterOnlineAtIn{ AccountName: accountName, ClusterName: clusterName, Timestamp: timestamppb.New(time.Now()), }); err != nil { - logger.Errorf(err, "marking cluster online") + logger.Error("marking cluster online", "err", err) return klErrors.NewE(err) } go func() { <-server.Context().Done() - logger.Debugf("server context has been closed") + logger.Debug("server context has been closed") delete(g.consumers, key) if err := consumer.Stop(context.TODO()); err != nil { - logger.Errorf(err, "while stopping consumer") + logger.Error("while stopping consumer", "err", err) } - logger.Infof("consumer is closed now") + logger.Info("consumer is closed now") }() if err := consumer.Consume(func(msg *types.ConsumeMsg) error { - logger.WithKV("subject", msg.Subject).Infof("read message from consumer") + logger.Info("read message from consumer", "subject", msg.Subject) defer func() { - logger.WithKV("subject", msg.Subject).Infof("dispatched message to agent") + logger.Info("dispatched message to agent", "subject", msg.Subject) }() return server.Send(&messages.Action{Message: msg.Payload}) }, types.ConsumeOpts{ OnError: func(error) error { - logger.Infof("error occurrred on agent side, while parsing/applying the message, ignoring as we don't want to block the queue") + logger.Info("error occurrred on agent side, while parsing/applying the message, ignoring as we don't want to block the queue") return nil }, }); err != nil { - logger.Errorf(err, "while consuming messages from consumer") + logger.Error("while consuming messages from consumer", "err", err) } return nil } -func (g *grpcServer) processConsoleResourceUpdate(ctx context.Context, accountName string, clusterName string, msg *messages.ResourceUpdate) (err error) { - g.resourceUpdatesCounter++ +type ResourceUpdateArgs struct { + logger *slog.Logger + updatesProducer UpdatesProducer - logger := g.logger.WithKV("accountName", accountName).WithKV("clusterName", clusterName).WithKV("component", "console-resource-update") - logger.Infof("[%v] received resource status update", g.resourceUpdatesCounter) - defer func() { - if err != nil { - err = errors.Wrap(err, fmt.Sprintf("[%v] (with ERROR) processed resource status update", g.clusterUpdatesCounter)) - logger.Errorf(err) - return - } - logger.Infof("[%v] processed resource status update", g.resourceUpdatesCounter) - }() + AccountName string + ClusterName string - b, err := msgOfficeT.MarshalResourceUpdate(msgOfficeT.ResourceUpdate{ - AccountName: accountName, - ClusterName: clusterName, - WatcherUpdate: msg.Message, - }) - if err != nil { - return errors.Wrap(err, "marshalling resource update") - } - - msgTopic := common.GetPlatformClusterMessagingTopic(accountName, clusterName, common.ConsoleReceiver, common.EventResourceUpdate) - if err := g.updatesProducer.Produce(ctx, types.ProduceMsg{ - Subject: msgTopic, - Payload: b, - }); err != nil { - return errors.Wrap(err, fmt.Sprintf("while producing resource update to topic %q", msgTopic)) - } - - logger.Infof("[%v] dispatched resource updates to topic %q", g.resourceUpdatesCounter, msgTopic) - return nil + Message *messages.ResourceUpdate } -func (g *grpcServer) processInfraResourceUpdate(ctx context.Context, accountName string, clusterName string, msg *messages.ResourceUpdate) (err error) { - g.infraUpdatesCounter++ - logger := g.logger.WithKV("accountName", accountName).WithKV("clusterName", clusterName).WithKV("component", "infra-resource-update") - - logger.Infof("[%v] received infra update", g.infraUpdatesCounter) - defer func() { - if err != nil { - err = errors.Wrap(err, fmt.Sprintf("[%v] (with ERROR) processed infra update", g.infraUpdatesCounter)) - logger.Errorf(err) - return - } - logger.Infof("[%v] processed infra update", g.infraUpdatesCounter) - }() - +func dispatchResourceUpdate(ctx context.Context, receiver common.MessageReceiver, args ResourceUpdateArgs) (err error) { b, err := msgOfficeT.MarshalResourceUpdate(msgOfficeT.ResourceUpdate{ - AccountName: accountName, - ClusterName: clusterName, - WatcherUpdate: msg.Message, + AccountName: args.AccountName, + ClusterName: args.ClusterName, + WatcherUpdate: args.Message.Message, }) if err != nil { - return errors.Wrap(err, "while marshaling resource update") - } - - msgTopic := common.GetPlatformClusterMessagingTopic(accountName, clusterName, common.InfraReceiver, common.EventResourceUpdate) - if err := g.updatesProducer.Produce(ctx, types.ProduceMsg{ - Subject: msgTopic, - Payload: b, - }); err != nil { - return errors.Wrap(err, fmt.Sprintf("while producing resource update to topic %q", msgTopic)) + return errors.Wrap(err, "marshalling resource update") } - logger.Infof("[%v] processed infra update", g.infraUpdatesCounter) - return nil -} - -func (g *grpcServer) processContainerRegistryResourceUpdate(ctx context.Context, accountName string, clusterName string, msg *messages.ResourceUpdate) (err error) { - g.crUpdatesCounter++ - logger := g.logger.WithKV("accountName", accountName).WithKV("clusterName", clusterName).WithKV("component", "container-registry-update") + subject := common.ReceiveFromAgentSubjectName(common.ReceiveFromAgentArgs{ + AccountName: args.AccountName, + ClusterName: args.ClusterName, + GVK: args.Message.Gvk, + Namespace: args.Message.Namespace, + Name: args.Message.Name, + }, receiver, common.EventResourceUpdate) - logger.Infof("[%v] received cr update", g.crUpdatesCounter) - defer func() { - if err != nil { - err = errors.Wrap(err, fmt.Sprintf("[%v] (with ERROR) processed cr update", g.crUpdatesCounter)) - logger.Errorf(err) - return - } - logger.Infof("[%v] processed cr update", g.crUpdatesCounter) - }() - - b, err := msgOfficeT.MarshalResourceUpdate(msgOfficeT.ResourceUpdate{ - AccountName: accountName, - ClusterName: clusterName, - WatcherUpdate: msg.Message, - }) - if err != nil { - return errors.Wrap(err, "while marshaling resource update") - } + args.logger.Debug("dispatching to", "subject", subject) - msgTopic := common.GetPlatformClusterMessagingTopic(accountName, clusterName, common.ContainerRegistryReceiver, common.EventResourceUpdate) - if err := g.updatesProducer.Produce(ctx, types.ProduceMsg{ - Subject: msgTopic, + if err := args.updatesProducer.Produce(ctx, types.ProduceMsg{ + Subject: subject, Payload: b, }); err != nil { - return errors.Wrap(err, fmt.Sprintf("while producing resource update to topic %q", msgTopic)) + return errors.Wrap(err, "producing resource update") } - logger.Infof("[%v] processed cr update", g.crUpdatesCounter) return nil } -func NewMessageOfficeServer(producer UpdatesProducer, jc *nats.JetstreamClient, ev *env.Env, d domain.Domain, logger logging.Logger, infraConn InfraGRPCClient) (messages.MessageDispatchServiceServer, error) { +func NewMessageOfficeServer(producer UpdatesProducer, jc *nats.JetstreamClient, ev *env.Env, d domain.Domain, logger *slog.Logger, infraConn InfraGRPCClient) (messages.MessageDispatchServiceServer, error) { return &grpcServer{ UnimplementedMessageDispatchServiceServer: messages.UnimplementedMessageDispatchServiceServer{}, infraClient: infra.NewInfraClient(infraConn), @@ -501,7 +478,8 @@ func NewMessageOfficeServer(producer UpdatesProducer, jc *nats.JetstreamClient, Durable: name, Description: "this consumer consumes messages from platform, and dispatches them to the tenant cluster via kloudlite agent", FilterSubjects: []string{ - common.GetTenantClusterMessagingTopic(accountName, clusterName), + fmt.Sprintf("%s.>", common.SendToAgentSubjectPrefix(accountName, clusterName)), + // common.GetTenantClusterMessagingTopic(accountName, clusterName), }, }, }) diff --git a/common/kafka-topic-name.go b/common/kafka-topic-name.go index ba46731a2..33616f279 100644 --- a/common/kafka-topic-name.go +++ b/common/kafka-topic-name.go @@ -1,6 +1,9 @@ package common -import "fmt" +import ( + "encoding/base64" + "fmt" +) type topicName string @@ -10,12 +13,32 @@ const ( NotificationTopicName topicName = "events.notification" ) -func GetKafkaTopicName(accountName string, clusterName string) string { - return fmt.Sprintf("kl-send-to-acc-%s-clus-%s", accountName, clusterName) +const ( + SendToAgentSubjectNamePrefix = "send-to-agent" + ReceiveFromAgentSubjectNamePrefix = "receive-from-agent" +) + +func SendToAgentSubjectPrefix(accountName string, clusterName string) string { + return fmt.Sprintf("%s.%s.%s", SendToAgentSubjectNamePrefix, accountName, clusterName) +} + +func ReceiveFromAgentSubjectPrefix(accountName string, clusterName string) string { + return fmt.Sprintf("%s.%s.%s", ReceiveFromAgentSubjectNamePrefix, accountName, clusterName) } -func GetTenantClusterMessagingTopic(accountName string, clusterName string) string { - return fmt.Sprintf("resource-sync.account-%s.cluster-%s.tenant", accountName, clusterName) +// func GetKafkaTopicName(accountName string, clusterName string) string { +// return fmt.Sprintf("kl-send-to-acc-%s-clus-%s", accountName, clusterName) +// } + +// func GetTenantClusterMessagingTopic(accountName string, clusterName string) string { +// // return fmt.Sprintf("resource-sync.account-%s.cluster-%s.tenant", accountName, clusterName) +// return fmt.Sprintf("%s.%s.%s", SendToAgentSubjectNamePrefix, accountName, clusterName) +// } + +func SendToAgentSubjectName(accountName string, clusterName string, gvk string, namespace string, name string) string { + slug := base64.RawStdEncoding.EncodeToString([]byte(fmt.Sprintf("%s.%s/%s", gvk, namespace, name))) + + return fmt.Sprintf("%s.%s.%s.%s", SendToAgentSubjectNamePrefix, accountName, clusterName, slug) } type platformEvent string @@ -25,17 +48,27 @@ const ( EventResourceUpdate platformEvent = "resource-update" ) -type messageReceiver string +type MessageReceiver string const ( - ConsoleReceiver messageReceiver = "kloudlite-console" - InfraReceiver messageReceiver = "kloudlite-infra" - ContainerRegistryReceiver messageReceiver = "kloudlite-cr" + ConsoleReceiver MessageReceiver = "kloudlite-console" + InfraReceiver MessageReceiver = "kloudlite-infra" + ContainerRegistryReceiver MessageReceiver = "kloudlite-cr" ) -func GetPlatformClusterMessagingTopic(accountName string, clusterName string, controller messageReceiver, ev platformEvent) string { - if accountName == "*" && clusterName == "*" { - return fmt.Sprintf("resource-sync.*.*.platform.%s.%s", controller, ev) - } - return fmt.Sprintf("resource-sync.account-%s.cluster-%s.platform.%s.%s", accountName, clusterName, controller, ev) +type ReceiveFromAgentArgs struct { + AccountName string + ClusterName string } + +func ReceiveFromAgentSubjectName(args ReceiveFromAgentArgs, receiver MessageReceiver, ev platformEvent) string { + slug := "*" + return fmt.Sprintf("%s.%s.%s.%s.%s.%s", ReceiveFromAgentSubjectNamePrefix, args.AccountName, args.ClusterName, slug, receiver, ev) +} + +// func GetPlatformClusterMessagingTopic(accountName string, clusterName string, controller messageReceiver, ev platformEvent) string { +// if accountName == "*" && clusterName == "*" { +// return fmt.Sprintf("resource-sync.*.*.platform.%s.%s", controller, ev) +// } +// return fmt.Sprintf("resource-sync.account-%s.cluster-%s.platform.%s.%s", accountName, clusterName, controller, ev) +// } diff --git a/pkg/functions/main.go b/pkg/functions/main.go index e1780bec6..ffe6b3c87 100644 --- a/pkg/functions/main.go +++ b/pkg/functions/main.go @@ -58,6 +58,14 @@ func CleanerNanoidOrDie(n int) string { return id } +// UUID returns a UUID string of the given size, if specified, otherwise a default size of 16 is used. +func UUID(size ...int) string { + if len(size) > 0 { + return nanoid.Must(size[0]) + } + return nanoid.Must(16) +} + func JsonConversion(from any, to any) error { if from == nil { return nil diff --git a/pkg/logging/slog-logger.go b/pkg/logging/slog-logger.go new file mode 100644 index 000000000..7fcc7c269 --- /dev/null +++ b/pkg/logging/slog-logger.go @@ -0,0 +1,33 @@ +package logging + +import ( + "io" + "log/slog" + "os" + + "github.com/charmbracelet/log" +) + +type SlogOptions struct { + Writer io.Writer + Prefix string + + ShowTimestamp bool + ShowCaller bool + ShowDebugLogs bool +} + +func NewSlogLogger(opts SlogOptions) *slog.Logger { + if opts.Writer == nil { + opts.Writer = os.Stderr + } + + level := log.InfoLevel + if opts.ShowDebugLogs { + level = log.DebugLevel + } + + logger := log.NewWithOptions(opts.Writer, log.Options{ReportCaller: opts.ShowCaller, ReportTimestamp: opts.ShowTimestamp, Prefix: opts.Prefix, Level: level}) + + return slog.New(logger) +} From e56337bf466e5184323f3368399672d3baec76d4 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Mon, 22 Jul 2024 01:25:55 +0530 Subject: [PATCH 2/9] fix: tenant-agent cleanup, and better reconnect handling - improves reconnection triggering and handling - improves logging, introduces `log/slog` --- apps/tenant-agent/Taskfile.yml | 2 +- apps/tenant-agent/main.go | 151 ++++++++++-------- apps/tenant-agent/vector-grpc-proxy-server.go | 24 ++- pkg/grpc/client.go | 81 ++++++++++ pkg/grpc/server.go | 22 ++- pkg/logging/slog-logger.go | 9 ++ 6 files changed, 208 insertions(+), 81 deletions(-) diff --git a/apps/tenant-agent/Taskfile.yml b/apps/tenant-agent/Taskfile.yml index 4790b029a..74044bccf 100644 --- a/apps/tenant-agent/Taskfile.yml +++ b/apps/tenant-agent/Taskfile.yml @@ -17,7 +17,7 @@ tasks: dotenv: - .secrets/env cmds: - - go run . --dev + - go run . --dev --debug build: cmds: diff --git a/apps/tenant-agent/main.go b/apps/tenant-agent/main.go index 7d61d7e91..5d899eb90 100644 --- a/apps/tenant-agent/main.go +++ b/apps/tenant-agent/main.go @@ -4,15 +4,16 @@ import ( "context" "encoding/json" "flag" - "log" + "fmt" + "log/slog" "os" "strings" + "sync" "time" "github.com/kloudlite/api/common" "github.com/kloudlite/api/pkg/errors" - "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" @@ -25,29 +26,36 @@ import ( proto_rpc "github.com/kloudlite/api/apps/tenant-agent/internal/proto-rpc" t "github.com/kloudlite/api/apps/tenant-agent/types" "github.com/kloudlite/operator/grpc-interfaces/grpc/messages" - libGrpc "github.com/kloudlite/operator/pkg/grpc" + + // libGrpc "github.com/kloudlite/operator/pkg/grpc" + libGrpc "github.com/kloudlite/api/pkg/grpc" "github.com/kloudlite/operator/pkg/kubectl" - "github.com/kloudlite/operator/pkg/logging" + "github.com/kloudlite/api/pkg/logging" apiErrors "k8s.io/apimachinery/pkg/api/errors" ) type grpcHandler struct { + mu sync.Mutex inMemCounter int64 yamlClient kubectl.YAMLClient - logger logging.Logger + logger *slog.Logger ev *env.Env msgDispatchCli messages.MessageDispatchServiceClient isDev bool } +func (g *grpcHandler) incrementCounter() { + g.mu.Lock() + defer g.mu.Unlock() + g.inMemCounter++ +} + const ( MaxConnectionDuration = 45 * time.Second ) func (g *grpcHandler) handleErrorOnApply(ctx context.Context, err error, msg t.AgentMessage) error { - g.logger.Debugf("[ERROR]: %s", err.Error()) - b, err := json.Marshal(t.AgentErrMessage{ AccountName: msg.AccountName, ClusterName: msg.ClusterName, @@ -71,7 +79,9 @@ func NewAuthorizedGrpcContext(ctx context.Context, accessToken string) context.C } func (g *grpcHandler) handleMessage(gctx context.Context, msg t.AgentMessage) error { - g.inMemCounter++ + g.incrementCounter() + start := time.Now() + logger := g.logger.With("counter", g.inMemCounter, "account", msg.AccountName, "cluster", msg.ClusterName, "action", msg.Action) ctx, cf := func() (context.Context, context.CancelFunc) { if g.isDev { return context.WithCancel(gctx) @@ -81,14 +91,14 @@ func (g *grpcHandler) handleMessage(gctx context.Context, msg t.AgentMessage) er defer cf() if msg.Object == nil { - g.logger.Infof("msg.Object is nil, could not process anything out of this message, ignoring ...") + logger.Info("msg.Object is nil, could not process anything out of this message, ignoring ...") return nil } obj := unstructured.Unstructured{Object: msg.Object} - mLogger := g.logger.WithKV("gvk", obj.GetObjectKind().GroupVersionKind().String()).WithKV("clusterName", msg.ClusterName).WithKV("accountName", msg.AccountName).WithKV("action", msg.Action) + mLogger := logger.With("gvk", obj.GetObjectKind().GroupVersionKind().String()) - mLogger.Infof("[%d] received message", g.inMemCounter) + mLogger.Info("received message") if len(strings.TrimSpace(msg.AccountName)) == 0 { return g.handleErrorOnApply(ctx, errors.Newf("field 'accountName' must be defined in message"), msg) @@ -110,53 +120,54 @@ func (g *grpcHandler) handleMessage(gctx context.Context, msg t.AgentMessage) er } if _, err := g.yamlClient.ApplyYAML(ctx, b); err != nil { - mLogger.Errorf(err, "[%d] [error-on-apply]: yaml: \n%s\n", g.inMemCounter, b) - mLogger.Infof("[%d] failed to process message", g.inMemCounter) + // mLogger.Errorf(err, "[%d] [error-on-apply]: yaml: \n%s\n", g.inMemCounter, b) + mLogger.Info("failed to process message") + fmt.Printf("[error-on-apply] yaml: \n%s\n", b) return g.handleErrorOnApply(ctx, err, msg) } - mLogger.Infof("[%d] processed message", g.inMemCounter) + mLogger.Info("processed message") } case t.ActionDelete: { if err := g.yamlClient.DeleteResource(ctx, &obj); err != nil { - mLogger.Infof("[%d] [error-on-delete]: %v", g.inMemCounter, err) + mLogger.Warn("while deleting resource, got", "err", err) if apiErrors.IsNotFound(err) { - mLogger.Infof("[%d] processed message, resource does not exist, might already be deleted", g.inMemCounter) + mLogger.Info("processed message, resource does not exist, might already be deleted") return g.handleErrorOnApply(ctx, err, msg) } - mLogger.Infof("[%d] failed to process message", g.inMemCounter) + mLogger.Info("failed to process message") } - mLogger.Infof("[%d] processed message", g.inMemCounter) + mLogger.Info("processed message") } case t.ActionRestart: { if err := g.yamlClient.RolloutRestart(ctx, kubectl.Deployment, obj.GetNamespace(), obj.GetLabels()); err != nil { return err } - mLogger.Infof("[%d] rolled out deployments", g.inMemCounter) + mLogger.Info("rolled out deployments") if err := g.yamlClient.RolloutRestart(ctx, kubectl.StatefulSet, obj.GetNamespace(), obj.GetLabels()); err != nil { return err } - mLogger.Infof("[%d] rolled out statefulsets", g.inMemCounter) - mLogger.Infof("[%d] processed message", g.inMemCounter) + mLogger.Info("rolled out statefulsets") } default: { err := errors.Newf("invalid action (%s)", msg.Action) - mLogger.Infof("[%d] [error]: %s", err.Error()) - mLogger.Infof("[%d] failed to process message", g.inMemCounter) + mLogger.Info("failed to process message, got", "err", err) return g.handleErrorOnApply(ctx, err, msg) } } + mLogger.Info("processed message", "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) + return nil } func (g *grpcHandler) ensureAccessToken() error { if g.ev.AccessToken == "" { - g.logger.Infof("waiting on clusterToken exchange for accessToken") + g.logger.Info("waiting on clusterToken exchange for accessToken") } ctx := NewAuthorizedGrpcContext(context.TODO(), g.ev.AccessToken) @@ -165,16 +176,16 @@ func (g *grpcHandler) ensureAccessToken() error { ProtocolVersion: g.ev.GrpcMessageProtocolVersion, }) if err != nil { - g.logger.Errorf(err, "validating access token") + g.logger.Error("validating access token, got", "err", err) validationOut = nil } if validationOut != nil && validationOut.Valid { - g.logger.Infof("accessToken is valid, proceeding with it ...") + g.logger.Info("accessToken is valid, proceeding with it ...") return nil } - g.logger.Infof("accessToken is invalid, requesting new accessToken ...") + g.logger.Debug("accessToken is invalid, requesting new accessToken ...") out, err := g.msgDispatchCli.GetAccessToken(ctx, &messages.GetAccessTokenIn{ ProtocolVersion: g.ev.GrpcMessageProtocolVersion, @@ -184,7 +195,7 @@ func (g *grpcHandler) ensureAccessToken() error { return errors.NewE(err) } - g.logger.Infof("valid access token has been obtained, persisting it in k8s secret (%s/%s)...", g.ev.AccessTokenSecretNamespace, g.ev.AccessTokenSecretName) + g.logger.Info("valid access token has been obtained, persisting it in k8s secret (%s/%s)...", g.ev.AccessTokenSecretNamespace, g.ev.AccessTokenSecretName) s, err := g.yamlClient.Client().CoreV1().Secrets(g.ev.AccessTokenSecretNamespace).Get(context.TODO(), g.ev.AccessTokenSecretName, metav1.GetOptions{}) if err != nil { @@ -216,19 +227,18 @@ func (g *grpcHandler) ensureAccessToken() error { } if err := g.yamlClient.Client().CoreV1().Pods(g.ev.ResourceWatcherNamespace).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(&podLabelSelector)}); err != nil { - g.logger.Errorf(err, "failed to delete pods for resource watcher") + g.logger.Error("failed to delete pods for resource watcher, got", "err", err) } - g.logger.Infof("deleted all pods for resource watcher, they will be recreated") + g.logger.Info("deleted all pods for resource watcher, they will be recreated") } return nil } -func (g *grpcHandler) run(rctx context.Context, cf context.CancelFunc) error { - defer cf() +func (g *grpcHandler) run(rctx context.Context) error { ctx := NewAuthorizedGrpcContext(rctx, g.ev.AccessToken) - g.logger.Infof("asking message office to start sending actions") + g.logger.Info("asking message office to start sending actions") msgActionsCli, err := g.msgDispatchCli.SendActions(ctx, &messages.Empty{}) if err != nil { return errors.NewE(err) @@ -243,23 +253,27 @@ func (g *grpcHandler) run(rctx context.Context, cf context.CancelFunc) error { a, err := msgActionsCli.Recv() if err != nil { if status.Code(err) == codes.Unavailable { - g.logger.Infof("server unavailable, (may be, Gateway Timed Out 504), reconnecting ...") + g.logger.Info("server unavailable, (may be, Gateway Timed Out 504), reconnecting ...") return nil } if status.Code(err) == codes.DeadlineExceeded { - g.logger.Infof("Connection Timed Out, reconnecting ...") + g.logger.Info("Connection Timed Out, reconnecting ...") + return nil + } + if status.Code(err) == codes.Canceled { + g.logger.Info("client is being closed, will reconnect") return nil } return err } if err := json.Unmarshal(a.Message, &msg); err != nil { - g.logger.Errorf(err, "[ERROR] while json unmarshal") + g.logger.Error("while unmarshalling agent message, got", "err", err) return errors.NewE(err) } if err := g.handleMessage(ctx, msg); err != nil { - g.logger.Errorf(err, "[ERROR] while handling message") + g.logger.Error("while handling agent message, got", "err", err) return errors.NewE(err) } } @@ -268,27 +282,32 @@ func (g *grpcHandler) run(rctx context.Context, cf context.CancelFunc) error { func main() { var isDev bool flag.BoolVar(&isDev, "dev", false, "--dev") + + var debug bool + flag.BoolVar(&debug, "debug", false, "--debug") + flag.Parse() ev := env.GetEnvOrDie() - logger := logging.NewOrDie(&logging.Options{Name: "kloudlite-agent", Dev: isDev}) + logger := logging.NewSlogLogger(logging.SlogOptions{ShowCaller: true, ShowDebugLogs: debug}) - logger.Infof("waiting for GRPC connection to happen") + logger.Debug("waiting for GRPC connection to happen") yamlClient := func() kubectl.YAMLClient { if isDev { - logger.Debugf("connecting to k8s over host addr (%s)", "localhost:8081") - return kubectl.NewYAMLClientOrDie(&rest.Config{Host: "localhost:8081"}, kubectl.YAMLClientOpts{Logger: logger}) + logger.Debug("connecting to k8s over", "local-addr", "localhost:8081") + return kubectl.NewYAMLClientOrDie(&rest.Config{Host: "localhost:8081"}, kubectl.YAMLClientOpts{}) } config, err := rest.InClusterConfig() if err != nil { panic(err) } - return kubectl.NewYAMLClientOrDie(config, kubectl.YAMLClientOpts{Logger: logger}) + return kubectl.NewYAMLClientOrDie(config, kubectl.YAMLClientOpts{}) }() g := grpcHandler{ + mu: sync.Mutex{}, inMemCounter: 0, yamlClient: yamlClient, logger: logger, @@ -303,13 +322,16 @@ func main() { errCh: nil, } - gs := libGrpc.NewGrpcServer(libGrpc.GrpcServerOpts{Logger: logger}) - proto_rpc.RegisterVectorServer(gs.GrpcServer, vps) + gs, err := libGrpc.NewGrpcServer(libGrpc.ServerOpts{Slogger: logger.With("component", "vector-grpc-proxy")}) + if err != nil { + logger.Error("failed to create grpc server, got", "err", err) + } + proto_rpc.RegisterVectorServer(gs, vps) go func() { err := gs.Listen(ev.VectorProxyGrpcServerAddr) if err != nil { - logger.Error(err) + logger.Error("failed to listen on vector grpc server, got", "err", err) os.Exit(1) } }() @@ -317,28 +339,16 @@ func main() { common.PrintReadyBanner() for { - logger.Debugf("trying to connect to message office grpc (%s)", ev.GrpcAddr) - cc, err := func() (*grpc.ClientConn, error) { - // if isDev { - // logger.Infof("attempting grpc connect over %s", ev.GrpcAddr) - // return libGrpc.Connect(ev.GrpcAddr, libGrpc.ConnectOpts{ - // SecureConnect: false, - // Timeout: 20 * time.Second, - // }) - // } - logger.Infof("attempting grpc connect over %s", ev.GrpcAddr) - return libGrpc.ConnectSecure(ev.GrpcAddr) - }() + cc, err := libGrpc.NewGrpcClientV2(ev.GrpcAddr, libGrpc.GrpcConnectOpts{TLSConnect: isDev, Logger: logger}) if err != nil { - log.Fatalf("Failed to connect after retries: %v", err) + logger.Error("failed to connect to message office, got", "err", err) + <-time.After(1 * time.Second) } - logger.Infof("GRPC connection to message-office (%s) successful", ev.GrpcAddr) - g.msgDispatchCli = messages.NewMessageDispatchServiceClient(cc) if err := g.ensureAccessToken(); err != nil { - logger.Errorf(err, "ensuring access token") + logger.Error("ensuring access token, got", "err", err) } ctx, cf := context.WithTimeout(context.TODO(), MaxConnectionDuration) @@ -347,26 +357,33 @@ func main() { vps.realVectorClient = proto_rpc.NewVectorClient(cc) vps.errCh = make(chan error, 1) + // go func() { + // <-time.After(10 * time.Second) + // vps.errCh <- errors.Newf("FAKE connection timeout") + // }() + go func() { - if err := g.run(ctx, cf); err != nil { - logger.Errorf(err, "running grpc sendActions") + defer cf() + if err := g.run(ctx); err != nil { + logger.Error("running grpc sendActions, got", "err", err) } }() select { case err := <-vps.errCh: { - logger.Errorf(err, "error from vector grpc proxy server") - cf() + logger.Error("from vector grpc proxy server, got", "err", err) } case <-ctx.Done(): { - logger.Debugf("run context done, reconnecting ...") + logger.Debug("MAX_CONNECTION_DURATION reached, will re-initialize connection") } } if err = cc.Close(); err != nil { - logger.Errorf(err, "Failed to close connection") + logger.Error("Failed to close connection, got", "err", err) } + + cf() } } diff --git a/apps/tenant-agent/vector-grpc-proxy-server.go b/apps/tenant-agent/vector-grpc-proxy-server.go index 7d4baede6..19e95a227 100644 --- a/apps/tenant-agent/vector-grpc-proxy-server.go +++ b/apps/tenant-agent/vector-grpc-proxy-server.go @@ -2,17 +2,20 @@ package main import ( "context" + "fmt" + "log/slog" + "time" proto_rpc "github.com/kloudlite/api/apps/tenant-agent/internal/proto-rpc" "github.com/kloudlite/api/pkg/errors" - "github.com/kloudlite/operator/pkg/logging" + fn "github.com/kloudlite/api/pkg/functions" "google.golang.org/grpc/metadata" ) type vectorGrpcProxyServer struct { proto_rpc.UnimplementedVectorServer realVectorClient proto_rpc.VectorClient - logger logging.Logger + logger *slog.Logger errCh chan error @@ -30,14 +33,16 @@ func (v *vectorGrpcProxyServer) PushEvents(ctx context.Context, msg *proto_rpc.P } outgoingCtx := metadata.NewOutgoingContext(ctx, metadata.Pairs("authorization", v.accessToken)) + logger := v.logger.With("request-id", fn.UUID()) v.pushEventsCounter++ - v.logger.Debugf("[%v] received push-events message", v.pushEventsCounter) - defer v.logger.Debugf("[%v] dispatched push-events message", v.pushEventsCounter) + logger.Debug("received push-events message") + start := time.Now() + defer logger.Info("dispatched push-events message", "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) per, err := v.realVectorClient.PushEvents(outgoingCtx, msg) if err != nil { - v.logger.Error(err) + v.logger.Error("while pushing events got", "err", err) if v.errCh != nil { v.errCh <- err } @@ -53,12 +58,15 @@ func (v *vectorGrpcProxyServer) HealthCheck(ctx context.Context, msg *proto_rpc. outgoingCtx := metadata.NewOutgoingContext(ctx, metadata.Pairs("authorization", v.accessToken)) + logger := v.logger.With("request-id", fn.UUID()) + v.healthCheckCounter++ - v.logger.Debugf("[%v] received health-check message", v.healthCheckCounter) - defer v.logger.Debugf("[%v] dispatched health-check message", v.healthCheckCounter) + logger.Debug("received health-check message") + start := time.Now() + defer logger.Debug("dispatched health-check message", "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) hcr, err := v.realVectorClient.HealthCheck(outgoingCtx, msg) if err != nil { - v.logger.Error(err) + v.logger.Error("while health-checking got", "err", err) if v.errCh != nil { v.errCh <- err } diff --git a/pkg/grpc/client.go b/pkg/grpc/client.go index f39594fe7..743a75240 100644 --- a/pkg/grpc/client.go +++ b/pkg/grpc/client.go @@ -1,8 +1,16 @@ package grpc import ( + "context" + "crypto/tls" + "fmt" + "log/slog" + "time" + "github.com/kloudlite/api/pkg/errors" "google.golang.org/grpc" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" ) @@ -26,3 +34,76 @@ func NewGrpcClient(serverAddr string) (Client, error) { } return &grpcClient{ClientConn: conn}, nil } + +type GrpcConnectOpts struct { + TLSConnect bool + Logger *slog.Logger + + ReconnectCheckInterval *time.Duration +} + +func NewGrpcClientV2(serverAddr string, opts GrpcConnectOpts) (Client, error) { + tc := insecure.NewCredentials() + if opts.TLSConnect { + tc = credentials.NewTLS(&tls.Config{InsecureSkipVerify: false}) + } + + if opts.Logger == nil { + opts.Logger = slog.Default() + } + if opts.ReconnectCheckInterval == nil { + rafter := 2 * time.Second + opts.ReconnectCheckInterval = &rafter + } + + opts.Logger.Debug("ATTEMPTING to connect") + conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(tc)) + if err != nil { + return nil, errors.NewE(err) + } + + gc := &grpcClient{ClientConn: conn} + + go func() { + attempt := 0 + prevState := connectivity.Idle + reconnecting := false + start := time.Now() + for { + cstate := conn.GetState() + + if cstate != connectivity.Ready { + opts.Logger.Warn("connection is not in ready state", "current", cstate) + + if cstate == connectivity.Shutdown { + opts.Logger.Info("connection is closing, shutting down...") + return + } + + if cstate != connectivity.Connecting && !reconnecting { + start = time.Now() + conn.Connect() // reconnecting + opts.Logger.Debug("ATTEMPTING re-connect") + reconnecting = true + attempt++ + continue + } + } + if cstate == connectivity.Ready && prevState != connectivity.Ready { + if attempt > 0 { + reconnecting = false + opts.Logger.Info("RE-CONNECTED", "attempt", attempt, "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) + } + opts.Logger.Info("CONNECTED", "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) + } + + prevState = cstate + // <-time.After(*opts.ReconnectCheckInterval) + ctx, cf := context.WithTimeout(context.TODO(), *opts.ReconnectCheckInterval) + conn.WaitForStateChange(ctx, cstate) + cf() + } + }() + + return gc, nil +} diff --git a/pkg/grpc/server.go b/pkg/grpc/server.go index e04952a98..b510c47e3 100644 --- a/pkg/grpc/server.go +++ b/pkg/grpc/server.go @@ -1,6 +1,7 @@ package grpc import ( + "log/slog" "net" "github.com/kloudlite/api/pkg/errors" @@ -16,12 +17,15 @@ type Server interface { } type ServerOpts struct { - Logger logging.Logger + Logger logging.Logger + Slogger *slog.Logger } type grpcServer struct { *grpc.Server - logger logging.Logger + // Deprecated: use slogger + logger logging.Logger + slogger *slog.Logger } func (g *grpcServer) Listen(addr string) error { @@ -29,7 +33,11 @@ func (g *grpcServer) Listen(addr string) error { if err != nil { return errors.NewEf(err, "could not listen to net/tcp server") } - g.logger.Infof("listening on %s", addr) + if g.slogger != nil { + g.slogger.Info("grpc server listening", "at", addr) + } else { + g.logger.Infof("listening on %s", addr) + } return g.Serve(listen) } @@ -50,13 +58,17 @@ func NewGrpcServer(opts ServerOpts) (Server, error) { grpc.StreamInterceptor(func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { p, ok := peer.FromContext(stream.Context()) if ok { - opts.Logger.Debugf("[Stream] New connection from %s", p.Addr.String()) + if opts.Slogger != nil { + opts.Slogger.Debug("new grpc connection", "from", p.Addr.String()) + } else { + opts.Logger.Debugf("[Stream] New connection from %s", p.Addr.String()) + } } return handler(srv, stream) }), ) - return &grpcServer{Server: server, logger: opts.Logger}, nil + return &grpcServer{Server: server, logger: opts.Logger, slogger: opts.Slogger}, nil } // Type guard to ensure grpcServer implements Server interface, at compile time diff --git a/pkg/logging/slog-logger.go b/pkg/logging/slog-logger.go index 7fcc7c269..472257e99 100644 --- a/pkg/logging/slog-logger.go +++ b/pkg/logging/slog-logger.go @@ -5,6 +5,7 @@ import ( "log/slog" "os" + "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/log" ) @@ -29,5 +30,13 @@ func NewSlogLogger(opts SlogOptions) *slog.Logger { logger := log.NewWithOptions(opts.Writer, log.Options{ReportCaller: opts.ShowCaller, ReportTimestamp: opts.ShowTimestamp, Prefix: opts.Prefix, Level: level}) + styles := log.DefaultStyles() + styles.Levels[log.DebugLevel] = styles.Levels[log.DebugLevel].Foreground(lipgloss.Color("#5b717f")) + + // styles.Key = lipgloss.NewStyle().Background(lipgloss.Color("#083e54")).Foreground(lipgloss.Color("#9dbdc9")).Bold(true) + styles.Key = lipgloss.NewStyle().Foreground(lipgloss.Color("#36cbfa")).Bold(true) + + logger.SetStyles(styles) + return slog.New(logger) } From 6f01011a2ae18de63c167b26002a3132345656c7 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 25 Jul 2024 15:12:52 +0530 Subject: [PATCH 3/9] fix(tenant-agent): fixes inconsistent reconnect behavior - cleans up lot of junk code - improves logging with `log/slog` --- apps/tenant-agent/main.go | 25 +++------------ apps/tenant-agent/vector-grpc-proxy-server.go | 32 +++++++++++-------- pkg/repos/db-repo-mongo.go | 11 ++++--- 3 files changed, 29 insertions(+), 39 deletions(-) diff --git a/apps/tenant-agent/main.go b/apps/tenant-agent/main.go index 5d899eb90..724159f61 100644 --- a/apps/tenant-agent/main.go +++ b/apps/tenant-agent/main.go @@ -27,7 +27,6 @@ import ( t "github.com/kloudlite/api/apps/tenant-agent/types" "github.com/kloudlite/operator/grpc-interfaces/grpc/messages" - // libGrpc "github.com/kloudlite/operator/pkg/grpc" libGrpc "github.com/kloudlite/api/pkg/grpc" "github.com/kloudlite/operator/pkg/kubectl" @@ -319,7 +318,6 @@ func main() { realVectorClient: nil, logger: logger, accessToken: ev.AccessToken, - errCh: nil, } gs, err := libGrpc.NewGrpcServer(libGrpc.ServerOpts{Slogger: logger.With("component", "vector-grpc-proxy")}) @@ -339,7 +337,7 @@ func main() { common.PrintReadyBanner() for { - cc, err := libGrpc.NewGrpcClientV2(ev.GrpcAddr, libGrpc.GrpcConnectOpts{TLSConnect: isDev, Logger: logger}) + cc, err := libGrpc.NewGrpcClientV2(ev.GrpcAddr, libGrpc.GrpcConnectOpts{TLSConnect: !isDev, Logger: logger}) if err != nil { logger.Error("failed to connect to message office, got", "err", err) <-time.After(1 * time.Second) @@ -355,12 +353,7 @@ func main() { vps.accessToken = g.ev.AccessToken vps.realVectorClient = proto_rpc.NewVectorClient(cc) - vps.errCh = make(chan error, 1) - - // go func() { - // <-time.After(10 * time.Second) - // vps.errCh <- errors.Newf("FAKE connection timeout") - // }() + vps.connCancelFn = cf go func() { defer cf() @@ -369,21 +362,11 @@ func main() { } }() - select { - case err := <-vps.errCh: - { - logger.Error("from vector grpc proxy server, got", "err", err) - } - case <-ctx.Done(): - { - logger.Debug("MAX_CONNECTION_DURATION reached, will re-initialize connection") - } - } + <-ctx.Done() + logger.Debug("MAX_CONNECTION_DURATION reached, will re-initialize connection") if err = cc.Close(); err != nil { logger.Error("Failed to close connection, got", "err", err) } - - cf() } } diff --git a/apps/tenant-agent/vector-grpc-proxy-server.go b/apps/tenant-agent/vector-grpc-proxy-server.go index 19e95a227..a55442d2e 100644 --- a/apps/tenant-agent/vector-grpc-proxy-server.go +++ b/apps/tenant-agent/vector-grpc-proxy-server.go @@ -9,15 +9,18 @@ import ( proto_rpc "github.com/kloudlite/api/apps/tenant-agent/internal/proto-rpc" "github.com/kloudlite/api/pkg/errors" fn "github.com/kloudlite/api/pkg/functions" + "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" ) type vectorGrpcProxyServer struct { proto_rpc.UnimplementedVectorServer + realVectorClient proto_rpc.VectorClient - logger *slog.Logger + connCancelFn context.CancelFunc - errCh chan error + logger *slog.Logger accessToken string accountName string @@ -33,21 +36,21 @@ func (v *vectorGrpcProxyServer) PushEvents(ctx context.Context, msg *proto_rpc.P } outgoingCtx := metadata.NewOutgoingContext(ctx, metadata.Pairs("authorization", v.accessToken)) - logger := v.logger.With("request-id", fn.UUID()) + logger := v.logger.With("request-id", fmt.Sprintf("%s-%s", fn.UUID(4), fn.UUID(4))) v.pushEventsCounter++ logger.Debug("received push-events message") start := time.Now() - defer logger.Info("dispatched push-events message", "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) - per, err := v.realVectorClient.PushEvents(outgoingCtx, msg) if err != nil { - v.logger.Error("while pushing events got", "err", err) - if v.errCh != nil { - v.errCh <- err + v.connCancelFn() + if status.Code(err) == codes.Canceled { + return nil, err } + v.logger.Error("FAILED to dispatch push-events message, got", "err", err) return nil, errors.NewE(err) } + logger.Debug("DISPATCHED push-events message", "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) return per, nil } @@ -58,19 +61,20 @@ func (v *vectorGrpcProxyServer) HealthCheck(ctx context.Context, msg *proto_rpc. outgoingCtx := metadata.NewOutgoingContext(ctx, metadata.Pairs("authorization", v.accessToken)) - logger := v.logger.With("request-id", fn.UUID()) + logger := v.logger.With("request-id", fmt.Sprintf("%s-%s", fn.UUID(4), fn.UUID(4))) v.healthCheckCounter++ - logger.Debug("received health-check message") + logger.Debug("RECEIVED health-check message") start := time.Now() - defer logger.Debug("dispatched health-check message", "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) hcr, err := v.realVectorClient.HealthCheck(outgoingCtx, msg) if err != nil { - v.logger.Error("while health-checking got", "err", err) - if v.errCh != nil { - v.errCh <- err + v.connCancelFn() + if status.Code(err) == codes.Canceled { + return nil, err } + v.logger.Error("FAILED to dispatch health-check message, got", "err", err) return nil, errors.NewE(err) } + logger.Debug("DISPATCHED health-check message", "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) return hcr, nil } diff --git a/pkg/repos/db-repo-mongo.go b/pkg/repos/db-repo-mongo.go index 5f7e2b2c7..3e2502f65 100644 --- a/pkg/repos/db-repo-mongo.go +++ b/pkg/repos/db-repo-mongo.go @@ -4,12 +4,13 @@ import ( "context" "encoding/json" "fmt" - "github.com/PaesslerAG/jsonpath" - "go.mongodb.org/mongo-driver/bson/primitive" "regexp" "strings" "time" + "github.com/PaesslerAG/jsonpath" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/bson" "go.uber.org/fx" @@ -136,7 +137,7 @@ func (repo *dbRepo[T]) findOne(ctx context.Context, filter Filter) (T, error) { item, err := bsonToStruct[T](one) if err != nil { if errors.Is(err, mongo.ErrNoDocuments) { - return item, errors.Newf("no document found") + return item, ErrNoDocuments } return item, errors.NewE(err) } @@ -399,12 +400,14 @@ func (repo *dbRepo[T]) UpdateMany(ctx context.Context, filter Filter, updatedDat return nil } +var ErrNoDocuments error = fmt.Errorf("no documents found") + func (repo *dbRepo[T]) Patch(ctx context.Context, filter Filter, patch Document, opts ...UpdateOpts) (T, error) { var x T res, err := repo.findOne(ctx, filter) if err != nil { - return x, errors.NewE(err) + return x, err } return repo.patchRecordByID(ctx, res.GetId(), patch, res.IsMarkedForDeletion(), opts...) From ce66b825ab2ccf732a14742e2529241ce8d9821b Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 25 Jul 2024 15:20:00 +0530 Subject: [PATCH 4/9] feat(message-office): implements workqueue stream subject, and improves logging - cleans up duplicated dispatch logic --- apps/message-office/internal/app/app.go | 10 +- .../internal/app/grpc-server.go | 107 ++++++++---------- .../internal/app/vector-proxy-server.go | 32 +++--- apps/message-office/internal/env/env.go | 5 +- .../internal/framework/framework.go | 5 +- apps/message-office/main.go | 12 ++ 6 files changed, 87 insertions(+), 84 deletions(-) diff --git a/apps/message-office/internal/app/app.go b/apps/message-office/internal/app/app.go index b00676951..e81c88f18 100644 --- a/apps/message-office/internal/app/app.go +++ b/apps/message-office/internal/app/app.go @@ -2,6 +2,7 @@ package app import ( "context" + "log/slog" "github.com/kloudlite/api/apps/message-office/internal/app/graph" "github.com/kloudlite/api/apps/message-office/internal/app/graph/generated" @@ -53,22 +54,21 @@ var Module = fx.Module("app", }, ), - fx.Provide(func(logger logging.Logger, jc *nats.JetstreamClient, producer UpdatesProducer, ev *env.Env, d domain.Domain, infraConn InfraGRPCClient) (messages.MessageDispatchServiceServer, error) { - return NewMessageOfficeServer(producer, jc, ev, d, logger.WithName("message-office"), infraConn) + fx.Provide(func(logger *slog.Logger, jc *nats.JetstreamClient, producer UpdatesProducer, ev *env.Env, d domain.Domain, infraCli infra.InfraClient) (messages.MessageDispatchServiceServer, error) { + return NewMessageOfficeServer(producer, jc, ev, d, logger.With("component", "message-office"), infraCli) }), fx.Provide(func(conn RealVectorGrpcClient) proto_rpc.VectorClient { return proto_rpc.NewVectorClient(conn) }), - fx.Provide(func(vectorGrpcClient proto_rpc.VectorClient, logger logging.Logger, d domain.Domain, ev *env.Env) proto_rpc.VectorServer { + fx.Provide(func(vectorGrpcClient proto_rpc.VectorClient, logger *slog.Logger, d domain.Domain, ev *env.Env) proto_rpc.VectorServer { return &vectorProxyServer{ realVectorClient: vectorGrpcClient, - logger: logger.WithName("vector-proxy"), + logger: logger, domain: d, tokenHashingSecret: ev.TokenHashingSecret, pushEventsCounter: 0, - healthCheckCounter: 0, } }), diff --git a/apps/message-office/internal/app/grpc-server.go b/apps/message-office/internal/app/grpc-server.go index 967a712f9..b4925e6a3 100644 --- a/apps/message-office/internal/app/grpc-server.go +++ b/apps/message-office/internal/app/grpc-server.go @@ -46,7 +46,7 @@ type ( domain domain.Domain - createConsumer func(ctx context.Context, accountName string, clusterName string) (messaging.Consumer, error) + createConsumer func(ctx context.Context, accountName string, clusterName string) (messaging.Consumer, string, error) } ) @@ -58,16 +58,8 @@ func (g *grpcServer) ReceiveConsoleResourceUpdate(ctx context.Context, msg *mess } start := time.Now() - logger := g.logger.With("accountName", accountName, "cluster", "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), clusterName, "for", common.ConsoleReceiver, "request-id", fn.UUID()) + logger := g.logger.With("account", accountName, "cluster", clusterName, "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) logger.Debug("RECEIVED resource update") - defer func() { - if err != nil { - logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) - return - } - - logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) - }() if err := dispatchResourceUpdate(ctx, common.ConsoleReceiver, ResourceUpdateArgs{ logger: logger, @@ -77,9 +69,11 @@ func (g *grpcServer) ReceiveConsoleResourceUpdate(ctx context.Context, msg *mess ClusterName: clusterName, Message: msg, }); err != nil { + logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) return nil, err } + logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) return &messages.Empty{}, nil } @@ -91,15 +85,8 @@ func (g *grpcServer) ReceiveContainerRegistryUpdate(ctx context.Context, msg *me } start := time.Now() - logger := g.logger.With("accountName", accountName, "cluster", "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), clusterName, "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) + logger := g.logger.With("account", accountName, "cluster", clusterName, "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) logger.Debug("RECEIVED resource update") - defer func() { - if err != nil { - logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) - return - } - logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) - }() if err := dispatchResourceUpdate(ctx, common.ContainerRegistryReceiver, ResourceUpdateArgs{ logger: logger, @@ -109,29 +96,25 @@ func (g *grpcServer) ReceiveContainerRegistryUpdate(ctx context.Context, msg *me ClusterName: clusterName, Message: msg, }); err != nil { + logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) return nil, err } + logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) return &messages.Empty{}, nil } // ReceiveError implements messages.MessageDispatchServiceServer. -func (g *grpcServer) ReceiveError(ctx context.Context, msg *messages.ErrorData) (*messages.Empty, error) { +func (g *grpcServer) ReceiveError(ctx context.Context, msg *messages.ErrorData) (_ *messages.Empty, err error) { accountName, clusterName, err := g.validateAndDecodeFromGrpcContext(ctx, g.ev.TokenHashingSecret) if err != nil { return nil, err } start := time.Now() - logger := g.logger.With("accountName", accountName, "cluster", "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), clusterName, "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) + logger := g.logger.With("account", accountName, "cluster", clusterName, "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) + logger.Debug("RECEIVED error-on-apply update") - defer func() { - if err != nil { - logger.Error("FAILED error-on-apply update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) - return - } - logger.Info("DISPATCHED error-on-apply update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) - }() if err := processError(ctx, ProcessErrorArgs{ logger: logger, @@ -141,9 +124,11 @@ func (g *grpcServer) ReceiveError(ctx context.Context, msg *messages.ErrorData) ClusterName: clusterName, Error: msg, }); err != nil { + logger.Error("FAILED error-on-apply update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) return nil, err } + logger.Info("DISPATCHED error-on-apply update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) return &messages.Empty{}, nil } @@ -155,15 +140,8 @@ func (g *grpcServer) ReceiveInfraResourceUpdate(ctx context.Context, msg *messag } start := time.Now() - logger := g.logger.With("accountName", accountName, "cluster", "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), clusterName, "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) + logger := g.logger.With("account", accountName, "cluster", clusterName, "GVK", msg.Gvk, "NN", fmt.Sprintf("%s/%s", msg.Namespace, msg.Name), "for", common.ContainerRegistryReceiver, "request-id", fn.UUID()) logger.Debug("RECEIVED resource update") - defer func() { - if err != nil { - logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) - return - } - logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) - }() if err := dispatchResourceUpdate(ctx, common.InfraReceiver, ResourceUpdateArgs{ logger: logger, @@ -173,9 +151,11 @@ func (g *grpcServer) ReceiveInfraResourceUpdate(ctx context.Context, msg *messag ClusterName: clusterName, Message: msg, }); err != nil { + logger.Error("FAILED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds()), "err", err) return nil, err } + logger.Info("DISPATCHED resource update", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) return &messages.Empty{}, nil } @@ -339,7 +319,7 @@ func processError(ctx context.Context, args ProcessErrorArgs) (err error) { // GetAccessToken implements messages.MessageDispatchServiceServer func (g *grpcServer) GetAccessToken(ctx context.Context, msg *messages.GetAccessTokenIn) (*messages.GetAccessTokenOut, error) { - g.logger.Info("request received for cluster-token (%q) exchange", msg.ClusterToken) + g.logger.Debug("request received for cluster-token exchange") ct, err := g.domain.FindClusterToken(ctx, msg.ClusterToken) if err != nil { @@ -350,7 +330,7 @@ func (g *grpcServer) GetAccessToken(ctx context.Context, msg *messages.GetAccess } s := encodeAccessToken(ct.AccountName, ct.ClusterName, msg.ClusterToken, g.ev.TokenHashingSecret) - g.logger.Info("SUCCESSFUL cluster-token exchange for account=%q, cluster=%q", ct.AccountName, ct.ClusterName) + g.logger.With("account", ct.AccountName, "cluster", ct.ClusterName).Info("SUCCESSFUL cluster-token exchange") return &messages.GetAccessTokenOut{ ProtocolVersion: g.ev.GrpcMessageProtocolVersion, @@ -366,21 +346,22 @@ func (g *grpcServer) SendActions(request *messages.Empty, server messages.Messag return klErrors.NewE(err) } - logger := g.logger.With("accountName", accountName, "clusterName", clusterName) - logger.Info("request received for sending actions to cluster") + logger := g.logger.With("account", accountName, "cluster", clusterName) + logger.Debug("request received for sending actions to cluster") defer func() { - logger.Info("stopped sending actions to cluster") + logger.Info("STOPPED transmitting messages to agent") }() key := fmt.Sprintf("%s/%s", accountName, clusterName) - consumer, err := g.createConsumer(server.Context(), accountName, clusterName) + consumer, subject, err := g.createConsumer(server.Context(), accountName, clusterName) if err != nil { return klErrors.NewE(err) } - // TODO: implement cluster online feature, so that we can mark the cluster as online/offline - logger.Info("consumer is available now") + logger = logger.With("subject", subject) + + logger.Info("READY to transmit messages to agent") if _, err := g.infraClient.MarkClusterOnlineAt(server.Context(), &infra.MarkClusterOnlineAtIn{ AccountName: accountName, @@ -398,22 +379,23 @@ func (g *grpcServer) SendActions(request *messages.Empty, server messages.Messag if err := consumer.Stop(context.TODO()); err != nil { logger.Error("while stopping consumer", "err", err) } - logger.Info("consumer is closed now") + logger.Debug("consumer is closed now") }() if err := consumer.Consume(func(msg *types.ConsumeMsg) error { + start := time.Now() logger.Info("read message from consumer", "subject", msg.Subject) defer func() { - logger.Info("dispatched message to agent", "subject", msg.Subject) + logger.Info("dispatched message to agent", "subject", msg.Subject, "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) }() return server.Send(&messages.Action{Message: msg.Payload}) }, types.ConsumeOpts{ - OnError: func(error) error { - logger.Info("error occurrred on agent side, while parsing/applying the message, ignoring as we don't want to block the queue") + OnError: func(err error) error { + logger.Warn("error occurrred on agent side, while parsing/applying the message, ignoring as we don't want to block the queue, got", "err", err) return nil }, }); err != nil { - logger.Error("while consuming messages from consumer", "err", err) + logger.Error("while consuming messages from consumer, got", "err", err) } return nil @@ -453,36 +435,39 @@ func dispatchResourceUpdate(ctx context.Context, receiver common.MessageReceiver Subject: subject, Payload: b, }); err != nil { - return errors.Wrap(err, "producing resource update") + return errors.Wrap(err, fmt.Sprintf("producing resource update to topic (%s)", subject)) } return nil } -func NewMessageOfficeServer(producer UpdatesProducer, jc *nats.JetstreamClient, ev *env.Env, d domain.Domain, logger *slog.Logger, infraConn InfraGRPCClient) (messages.MessageDispatchServiceServer, error) { +func NewMessageOfficeServer(producer UpdatesProducer, jc *nats.JetstreamClient, ev *env.Env, d domain.Domain, logger *slog.Logger, infraCli infra.InfraClient) (messages.MessageDispatchServiceServer, error) { return &grpcServer{ UnimplementedMessageDispatchServiceServer: messages.UnimplementedMessageDispatchServiceServer{}, - infraClient: infra.NewInfraClient(infraConn), + infraClient: infraCli, logger: logger, updatesProducer: producer, consumers: make(map[string]messaging.Consumer), ev: ev, domain: d, - createConsumer: func(ctx context.Context, accountName string, clusterName string) (messaging.Consumer, error) { + createConsumer: func(ctx context.Context, accountName string, clusterName string) (messaging.Consumer, string, error) { name := fmt.Sprintf("tenant-consumer-for-account-%s-cluster-%s", accountName, clusterName) - return msg_nats.NewJetstreamConsumer(ctx, jc, msg_nats.JetstreamConsumerArgs{ - Stream: ev.NatsStream, + filterSubject := fmt.Sprintf("%s.>", common.SendToAgentSubjectPrefix(accountName, clusterName)) + + jc, err := msg_nats.NewJetstreamConsumer(ctx, jc, msg_nats.JetstreamConsumerArgs{ + Stream: ev.NatsSendToAgentStream, ConsumerConfig: msg_nats.ConsumerConfig{ - Name: name, - Durable: name, - Description: "this consumer consumes messages from platform, and dispatches them to the tenant cluster via kloudlite agent", - FilterSubjects: []string{ - fmt.Sprintf("%s.>", common.SendToAgentSubjectPrefix(accountName, clusterName)), - // common.GetTenantClusterMessagingTopic(accountName, clusterName), - }, + Name: name, + Durable: name, + Description: "this consumer consumes messages from platform, and dispatches them to the tenant cluster via kloudlite agent", + FilterSubjects: []string{filterSubject}, }, }) + if err != nil { + return nil, "", klErrors.NewEf(err, "creating consumer") + } + return jc, filterSubject, nil }, }, nil } diff --git a/apps/message-office/internal/app/vector-proxy-server.go b/apps/message-office/internal/app/vector-proxy-server.go index 1551781aa..a2f93a408 100644 --- a/apps/message-office/internal/app/vector-proxy-server.go +++ b/apps/message-office/internal/app/vector-proxy-server.go @@ -2,22 +2,24 @@ package app import ( "context" + "log/slog" + "sync" "github.com/kloudlite/api/pkg/errors" proto_rpc "github.com/kloudlite/api/apps/message-office/internal/app/proto-rpc" "github.com/kloudlite/api/apps/message-office/internal/domain" - "github.com/kloudlite/api/pkg/logging" ) type vectorProxyServer struct { proto_rpc.UnimplementedVectorServer realVectorClient proto_rpc.VectorClient - logger logging.Logger + logger *slog.Logger domain domain.Domain tokenHashingSecret string - pushEventsCounter int - healthCheckCounter int + + sync.Mutex + pushEventsCounter int } func (v *vectorProxyServer) PushEvents(ctx context.Context, msg *proto_rpc.PushEventsRequest) (*proto_rpc.PushEventsResponse, error) { @@ -26,16 +28,20 @@ func (v *vectorProxyServer) PushEvents(ctx context.Context, msg *proto_rpc.PushE return nil, errors.NewE(err) } - logger := v.logger.WithKV("accountName", accountName, "clusterName", clusterName) + v.Lock() v.pushEventsCounter++ - logger.Debugf("[%v] received push-events message", v.pushEventsCounter) - defer logger.Debugf("[%v] dispatched push-events message to vector aggregator", v.pushEventsCounter) + v.Unlock() + + logger := v.logger.With("account", accountName, "cluster", clusterName, "counter", v.pushEventsCounter) + + logger.Debug("RECEIVED push-events message") per, err := v.realVectorClient.PushEvents(ctx, msg) if err != nil { - logger.Errorf(err) + logger.Error("FAILED to dispatch push-events message, got", "err", err) return nil, errors.NewE(err) } + logger.Debug("DISPATCHED push-events message") return per, nil } @@ -45,15 +51,13 @@ func (v *vectorProxyServer) HealthCheck(ctx context.Context, msg *proto_rpc.Heal return nil, errors.NewE(err) } - logger := v.logger.WithKV("accountName", accountName, "clusterName", clusterName) - v.healthCheckCounter++ - logger.Debugf("[%v] received health-check message", v.healthCheckCounter) - defer logger.Debugf("[%v] dispatched health-check message to vector aggregator", v.healthCheckCounter) - + logger := v.logger.With("account", accountName, "cluster", clusterName) + logger.Debug("RECEIVED health-check message") hcr, err := v.realVectorClient.HealthCheck(ctx, msg) if err != nil { - logger.Errorf(err) + logger.Error("FAILED to dispatch health-check message, got", "err", err) return nil, errors.NewE(err) } + logger.Debug("DISPATCHED health-check message") return hcr, nil } diff --git a/apps/message-office/internal/env/env.go b/apps/message-office/internal/env/env.go index 788fd1f88..d7e353969 100644 --- a/apps/message-office/internal/env/env.go +++ b/apps/message-office/internal/env/env.go @@ -5,8 +5,9 @@ import ( ) type Env struct { - NatsUrl string `env:"NATS_URL" required:"true"` - NatsStream string `env:"NATS_STREAM" required:"true"` + NatsUrl string `env:"NATS_URL" required:"true"` + NatsSendToAgentStream string `env:"NATS_SEND_TO_AGENT_STREAM" required:"true"` + NatsReceiveFromAgentStream string `env:"NATS_RECEIVE_FROM_AGENT_STREAM" required:"true"` PlatformAccessToken string `env:"PLATFORM_ACCESS_TOKEN" required:"true"` diff --git a/apps/message-office/internal/framework/framework.go b/apps/message-office/internal/framework/framework.go index e0836c4eb..8ad128beb 100644 --- a/apps/message-office/internal/framework/framework.go +++ b/apps/message-office/internal/framework/framework.go @@ -3,6 +3,7 @@ package framework import ( "context" "fmt" + "github.com/kloudlite/api/pkg/errors" "go.uber.org/fx" @@ -85,11 +86,11 @@ var Module = fx.Module("framework", }) }), - fx.Invoke(func(lf fx.Lifecycle,logr logging.Logger, server app.ExternalGrpcServer, ev *env.Env) { + fx.Invoke(func(lf fx.Lifecycle, logr logging.Logger, server app.ExternalGrpcServer, ev *env.Env) { lf.Append(fx.Hook{ OnStart: func(context.Context) error { go func() { - if err:=server.Listen(fmt.Sprintf(":%d", ev.ExternalGrpcPort)); err!=nil{ + if err := server.Listen(fmt.Sprintf(":%d", ev.ExternalGrpcPort)); err != nil { logr.Errorf(err, "while starting external grpc server") } }() diff --git a/apps/message-office/main.go b/apps/message-office/main.go index a4966c5f2..8b5e8585f 100644 --- a/apps/message-office/main.go +++ b/apps/message-office/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "log/slog" "os" "time" @@ -19,6 +20,10 @@ import ( func main() { var isDev bool flag.BoolVar(&isDev, "dev", false, "--dev") + + var debug bool + flag.BoolVar(&debug, "debug", false, "--debug") + flag.Parse() logger, err := logging.New(&logging.Options{Name: "message-office", ShowDebugLog: isDev, HideCallerTrace: false}) @@ -39,6 +44,13 @@ func main() { }, ), + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: debug, + }) + }), + fx.Provide(func() (*rest.Config, error) { if isDev { return &rest.Config{ From 32016cbf8e7ac71f694dd5d5ac8ea7512ef9a0e8 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 25 Jul 2024 15:40:38 +0530 Subject: [PATCH 5/9] chore: excluding /_healthy from fiber logs - adds option to set SlogLogger as a global slog logger - grpc client auto-reconnect updates --- pkg/grpc/client.go | 1 + pkg/http-server/http-server.go | 26 ++++++++++++++++++-------- pkg/logging/slog-logger.go | 19 ++++++++++++++++--- pkg/repos/db-repo-mongo.go | 9 +++++---- pkg/repos/mongo.go | 8 ++++---- 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/pkg/grpc/client.go b/pkg/grpc/client.go index 743a75240..075514ee5 100644 --- a/pkg/grpc/client.go +++ b/pkg/grpc/client.go @@ -91,6 +91,7 @@ func NewGrpcClientV2(serverAddr string, opts GrpcConnectOpts) (Client, error) { } if cstate == connectivity.Ready && prevState != connectivity.Ready { if attempt > 0 { + attempt = 0 reconnecting = false opts.Logger.Info("RE-CONNECTED", "attempt", attempt, "took", fmt.Sprintf("%.3fs", time.Since(start).Seconds())) } diff --git a/pkg/http-server/http-server.go b/pkg/http-server/http-server.go index c602f0e04..5db89e9ed 100644 --- a/pkg/http-server/http-server.go +++ b/pkg/http-server/http-server.go @@ -19,6 +19,7 @@ import ( "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" l "github.com/gofiber/fiber/v2/middleware/logger" + "github.com/gofiber/fiber/v2/middleware/skip" "github.com/kloudlite/api/pkg/logging" ) @@ -75,21 +76,30 @@ type ServerArgs struct { func NewServer(args ServerArgs) Server { app := fiber.New(fiber.Config{ + // Prefork: true, + DisableStartupMessage: true, ErrorHandler: func(ctx *fiber.Ctx, err error) error { args.Logger.Errorf(err) return errors.NewE(err) }, }) - app.Use( - l.New( - l.Config{ - Format: "${time} ${status} - ${method} ${latency} \t ${path} \n", - TimeFormat: "02-Jan-2006 15:04:05", - TimeZone: "Asia/Kolkata", - }, - ), + + loggerMiddleware := l.New( + l.Config{ + CustomTags: map[string]l.LogFunc{}, + Format: "${time} ${status} - ${method} ${latency} \t ${path} \n", + TimeFormat: "02-Jan-2006 15:04:05", + TimeZone: "Asia/Kolkata", + TimeInterval: 0, + Output: nil, + DisableColors: false, + }, ) + app.Use(skip.New(loggerMiddleware, func(c *fiber.Ctx) bool { + return c.Path() == "/_healthy" + })) + if args.CorsAllowOrigins != nil { app.Use( cors.New( diff --git a/pkg/logging/slog-logger.go b/pkg/logging/slog-logger.go index 472257e99..1e0e02d29 100644 --- a/pkg/logging/slog-logger.go +++ b/pkg/logging/slog-logger.go @@ -16,6 +16,8 @@ type SlogOptions struct { ShowTimestamp bool ShowCaller bool ShowDebugLogs bool + + SetAsDefaultLogger bool } func NewSlogLogger(opts SlogOptions) *slog.Logger { @@ -28,15 +30,26 @@ func NewSlogLogger(opts SlogOptions) *slog.Logger { level = log.DebugLevel } - logger := log.NewWithOptions(opts.Writer, log.Options{ReportCaller: opts.ShowCaller, ReportTimestamp: opts.ShowTimestamp, Prefix: opts.Prefix, Level: level}) + logger := log.NewWithOptions(opts.Writer, log.Options{ + ReportCaller: opts.ShowCaller, + ReportTimestamp: opts.ShowTimestamp, + Prefix: opts.Prefix, + Level: level, + }) styles := log.DefaultStyles() styles.Levels[log.DebugLevel] = styles.Levels[log.DebugLevel].Foreground(lipgloss.Color("#5b717f")) + styles.Levels[log.InfoLevel] = styles.Levels[log.InfoLevel].Foreground(lipgloss.Color("#36cbfa")) - // styles.Key = lipgloss.NewStyle().Background(lipgloss.Color("#083e54")).Foreground(lipgloss.Color("#9dbdc9")).Bold(true) styles.Key = lipgloss.NewStyle().Foreground(lipgloss.Color("#36cbfa")).Bold(true) logger.SetStyles(styles) - return slog.New(logger) + l := slog.New(logger) + + if opts.SetAsDefaultLogger { + slog.SetDefault(l) + } + + return l } diff --git a/pkg/repos/db-repo-mongo.go b/pkg/repos/db-repo-mongo.go index 3e2502f65..e5b2082a1 100644 --- a/pkg/repos/db-repo-mongo.go +++ b/pkg/repos/db-repo-mongo.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log/slog" "regexp" "strings" "time" @@ -16,7 +17,6 @@ import ( "github.com/kloudlite/api/pkg/errors" fn "github.com/kloudlite/api/pkg/functions" - "github.com/kloudlite/api/pkg/logging" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) @@ -725,16 +725,17 @@ func NewFxMongoRepo[T Entity](collectionName, shortName string, indexFields []In }, ), fx.Invoke( - func(lifecycle fx.Lifecycle, repo DbRepo[T], logger logging.Logger) { + // func(lifecycle fx.Lifecycle, repo DbRepo[T], logger logging.Logger) { + func(lifecycle fx.Lifecycle, repo DbRepo[T]) { lifecycle.Append( fx.Hook{ OnStart: func(ctx context.Context) error { go func() { err := repo.IndexFields(ctx, indexFields) if err != nil { - logger.Errorf(err, "failed to update indexes on DB for repo %T", repo) + slog.Error("failed to update indexes", "collection", collectionName, "err", err) } - logger.Infof("indexes updated on DB for repo %T", repo) + slog.Info("indexes updated on DB", "collection", collectionName) }() return nil }, diff --git a/pkg/repos/mongo.go b/pkg/repos/mongo.go index a988a87de..74ebbc9b4 100644 --- a/pkg/repos/mongo.go +++ b/pkg/repos/mongo.go @@ -2,10 +2,10 @@ package repos import ( "context" + "log/slog" "time" "github.com/kloudlite/api/pkg/errors" - "github.com/kloudlite/api/pkg/logging" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/fx" @@ -33,14 +33,14 @@ func NewMongoClientFx[T MongoConfig]() fx.Option { return NewMongoDatabase(ctx, url, dbName) }), - fx.Invoke(func(db *mongo.Database, logger logging.Logger, lifecycle fx.Lifecycle) { + fx.Invoke(func(db *mongo.Database, lifecycle fx.Lifecycle) { lifecycle.Append(fx.Hook{ OnStart: func(ctx context.Context) error { if err := db.Client().Ping(ctx, nil); err != nil { - // if err := db.Client().Ping(ctx, readpref.Primary()); err != nil { + // if err := db.Client().Ping(ctx, readpref.Primary()); err != nil { return errors.NewEf(err, "could not ping Mongo") } - logger.Infof("connected to mongodb database: %s", db.Name()) + slog.Info("connected to mongodb database", "db", db.Name()) return nil }, From 1e547589298e33f34eab1f7af6cdea6fab2791ce Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 25 Jul 2024 15:44:31 +0530 Subject: [PATCH 6/9] chore: fixes/improves logging for nats client --- pkg/messaging/examples/nats-consumer/main.go | 4 +-- pkg/messaging/nats/jetstream-consumer.go | 18 +++++++----- pkg/nats/client.go | 31 ++++++++------------ pkg/nats/jetstream-client.go | 5 ++-- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/pkg/messaging/examples/nats-consumer/main.go b/pkg/messaging/examples/nats-consumer/main.go index 10c49a5db..58adeaaec 100644 --- a/pkg/messaging/examples/nats-consumer/main.go +++ b/pkg/messaging/examples/nats-consumer/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "fmt" "log" "os" @@ -30,8 +29,7 @@ func main() { log.Fatal(err) } - subjectBase := fmt.Sprintf("resource-sync.*.*.platform.kloudlite-console.resource-update") - _ = subjectBase + subjectBase := "resource-sync.*.*.platform.kloudlite-console.resource-update" consumer, err = msg_nats.NewJetstreamConsumer(context.TODO(), jc, msg_nats.JetstreamConsumerArgs{ Stream: natsStream, diff --git a/pkg/messaging/nats/jetstream-consumer.go b/pkg/messaging/nats/jetstream-consumer.go index eb193d2c5..dee3b0c66 100644 --- a/pkg/messaging/nats/jetstream-consumer.go +++ b/pkg/messaging/nats/jetstream-consumer.go @@ -23,18 +23,22 @@ type JetstreamConsumer struct { // Consume implements messaging.Consumer. func (jc *JetstreamConsumer) Consume(consumeFn func(msg *types.ConsumeMsg) error, opts types.ConsumeOpts) error { cctx, err := jc.consumer.Consume(func(msg jetstream.Msg) { + logger := jc.client.Logger.With("subject", msg.Subject()) + mm, err := msg.Metadata() if err != nil { if err := msg.Nak(); err != nil { - jc.client.Logger.Errorf(err, "while consuming message from subject: %s, sending NACK", msg.Subject()) + logger.Error("failed to send NAK", "err", err) return } return } + logger = logger.With("consumer", mm.Consumer, "stream", mm.Stream) + if err = msg.InProgress(); err != nil { if err := msg.Nak(); err != nil { - jc.client.Logger.Errorf(err, "while consuming message from subject: %s, sending NACK", msg.Subject()) + logger.Error("failed to send NAK", "err", err) return } return @@ -46,9 +50,8 @@ func (jc *JetstreamConsumer) Consume(consumeFn func(msg *types.ConsumeMsg) error Payload: msg.Data(), }); err != nil { if opts.OnError == nil { - jc.client.Logger.Errorf(err, "while consuming message from subject: %s, sending NACK", msg.Subject()) if err := msg.Nak(); err != nil { - jc.client.Logger.Errorf(err, "while consuming message from subject: %s, sending NACK", msg.Subject()) + logger.Error("failed to send NAK", "err", err) return } return @@ -56,9 +59,8 @@ func (jc *JetstreamConsumer) Consume(consumeFn func(msg *types.ConsumeMsg) error if opts.OnError != nil { if err := opts.OnError(err); err != nil { - jc.client.Logger.Errorf(err, "while consuming message from subject: %s, sending NACK", msg.Subject()) if err := msg.Nak(); err != nil { - jc.client.Logger.Errorf(err, "while consuming message from subject: %s, sending NACK", msg.Subject()) + logger.Error("failed to send NAK", "err", err) return } return @@ -67,10 +69,10 @@ func (jc *JetstreamConsumer) Consume(consumeFn func(msg *types.ConsumeMsg) error } if err := msg.Ack(); err != nil { - jc.client.Logger.Errorf(err, "while consuming message from subject: %s, sending ACK", msg.Subject()) + logger.Error("failed to send ACK, got", "err", err) return } - jc.client.Logger.Infof("acknowledged message, stream: %s, consumer: %s", mm.Stream, mm.Consumer) + logger.Debug("CONSUMED message", "stream", mm.Stream, "consumer", mm.Consumer) }) if err != nil { return errors.NewE(err) diff --git a/pkg/nats/client.go b/pkg/nats/client.go index a6344bcbf..01479b7dd 100644 --- a/pkg/nats/client.go +++ b/pkg/nats/client.go @@ -2,17 +2,17 @@ package nats import ( "context" - "fmt" - "github.com/kloudlite/api/pkg/errors" + "log/slog" "time" - "github.com/kloudlite/api/pkg/logging" + "github.com/kloudlite/api/pkg/errors" + "github.com/nats-io/nats.go" ) type Client struct { Conn *nats.Conn - logger logging.Logger + logger *slog.Logger } // Close implements Client. @@ -33,7 +33,7 @@ type ClientOpts struct { Name string // https://pkg.go.dev/github.com/nats-io/nats.go#Options Servers []string - Logger logging.Logger + Logger *slog.Logger DisconnectedCB func() ReconnectedCB func() @@ -47,14 +47,7 @@ func NewClient(url string, opts ClientOpts) (*Client, error) { } if opts.Logger == nil { - var err error - opts.Logger, err = logging.New(&logging.Options{ - Name: fmt.Sprintf("nats-client:%s", opts.Name), - Dev: true, - }) - if err != nil { - return nil, errors.NewE(err) - } + opts.Logger = slog.Default() } connectOpts := []nats.Option{ @@ -91,34 +84,34 @@ func NewClient(url string, opts ClientOpts) (*Client, error) { opts.ClosedCB() return } - opts.Logger.Infof("[%s] connection closed with nats server", opts.Name) + opts.Logger.Warn("connection closed with nats server", "name", opts.Name) }, DisconnectedCB: func(*nats.Conn) { if opts.DisconnectedCB != nil { opts.DisconnectedCB() return } - opts.Logger.Infof("[%s] disconnected with nats server", opts.Name) + opts.Logger.Warn("disconnected with nats server", "name", opts.Name) }, ConnectedCB: func(*nats.Conn) { if opts.ConnectedCB != nil { opts.ConnectedCB() return } - opts.Logger.Infof("[%s] connected to nats server", opts.Name) + opts.Logger.Info("connected to nats server", "name", opts.Name) }, ReconnectedCB: func(*nats.Conn) { if opts.ReconnectedCB != nil { opts.ReconnectedCB() return } - opts.Logger.Infof("[%s] reconnected to nats server", opts.Name) + opts.Logger.Info("re-connected to nats server", "name", opts.Name) }, DiscoveredServersCB: func(c *nats.Conn) { - opts.Logger.Infof("[%s] discovered additional nats servers: %+v\n", c.DiscoveredServers()) + opts.Logger.Info("discovered additional nats servers", "servers", c.DiscoveredServers()) }, AsyncErrorCB: func(_ *nats.Conn, sub *nats.Subscription, err error) { - opts.Logger.Warnf("[%s] async error received in subject(%s): %v", opts.Name, sub.Subject, err) + opts.Logger.Warn("got async error for", "name", opts.Name, "subject", sub.Subject, "err", err) }, RetryOnFailedConnect: true, Compression: true, diff --git a/pkg/nats/jetstream-client.go b/pkg/nats/jetstream-client.go index a4bc4ea3d..636681838 100644 --- a/pkg/nats/jetstream-client.go +++ b/pkg/nats/jetstream-client.go @@ -2,15 +2,16 @@ package nats import ( "context" + "log/slog" + "github.com/kloudlite/api/pkg/errors" - "github.com/kloudlite/api/pkg/logging" "github.com/nats-io/nats.go/jetstream" ) type JetstreamClient struct { Jetstream jetstream.JetStream - Logger logging.Logger + Logger *slog.Logger } type ConsumerManager interface { From b1c939d3d122f6a8c267fa58752106c61e9fe516 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 25 Jul 2024 16:00:21 +0530 Subject: [PATCH 7/9] fix: nats subject changes, and improves logging --- apps/console/internal/app/app.go | 17 ++--- apps/console/internal/app/dns-server.go | 17 +++-- .../internal/app/process-error-on-apply.go | 36 ++++++---- .../internal/app/process-resource-updates.go | 68 ++++++++++--------- apps/console/internal/domain/domain.go | 15 ++-- apps/console/internal/env/env.go | 6 +- apps/console/internal/framework/framework.go | 9 ++- apps/console/main.go | 8 +++ common/kafka-topic-name.go | 25 ++++--- 9 files changed, 119 insertions(+), 82 deletions(-) diff --git a/apps/console/internal/app/app.go b/apps/console/internal/app/app.go index 7c01f75d2..9bf9d2fe4 100644 --- a/apps/console/internal/app/app.go +++ b/apps/console/internal/app/app.go @@ -2,6 +2,7 @@ package app import ( "context" + "log/slog" "github.com/kloudlite/api/grpc-interfaces/kloudlite.io/rpc/console" "github.com/kloudlite/api/pkg/k8s" @@ -167,7 +168,7 @@ var Module = fx.Module("app", topic := common.ReceiveFromAgentSubjectName(common.ReceiveFromAgentArgs{AccountName: "*", ClusterName: "*"}, common.ConsoleReceiver, common.EventErrorOnApply) consumerName := "console:error-on-apply" return msg_nats.NewJetstreamConsumer(context.TODO(), jc, msg_nats.JetstreamConsumerArgs{ - Stream: ev.NatsResourceSyncStream, + Stream: ev.NatsReceiveFromAgentStream, ConsumerConfig: msg_nats.ConsumerConfig{ Name: consumerName, Durable: consumerName, @@ -177,7 +178,7 @@ var Module = fx.Module("app", }) }), - fx.Invoke(func(lf fx.Lifecycle, consumer ErrorOnApplyConsumer, d domain.Domain, logger logging.Logger) { + fx.Invoke(func(lf fx.Lifecycle, consumer ErrorOnApplyConsumer, d domain.Domain, logger *slog.Logger) { lf.Append(fx.Hook{ OnStart: func(context.Context) error { go ProcessErrorOnApply(consumer, d, logger) @@ -194,7 +195,7 @@ var Module = fx.Module("app", consumerName := "console:resource-updates" return msg_nats.NewJetstreamConsumer(context.TODO(), jc, msg_nats.JetstreamConsumerArgs{ - Stream: ev.NatsResourceSyncStream, + Stream: ev.NatsReceiveFromAgentStream, ConsumerConfig: msg_nats.ConsumerConfig{ Name: consumerName, Durable: consumerName, @@ -204,7 +205,7 @@ var Module = fx.Module("app", }) }), - fx.Invoke(func(lf fx.Lifecycle, consumer ResourceUpdateConsumer, d domain.Domain, logger logging.Logger) { + fx.Invoke(func(lf fx.Lifecycle, consumer ResourceUpdateConsumer, d domain.Domain, logger *slog.Logger) { lf.Append(fx.Hook{ OnStart: func(context.Context) error { go ProcessResourceUpdates(consumer, d, logger) @@ -220,7 +221,7 @@ var Module = fx.Module("app", return domain.NewSvcBindingDomain(svcBindingRepo) }), - fx.Provide(func(logger logging.Logger, sbd domain.ServiceBindingDomain, ev *env.Env) *dnsHandler { + fx.Provide(func(logger *slog.Logger, sbd domain.ServiceBindingDomain, ev *env.Env) *dnsHandler { return &dnsHandler{ logger: logger, serviceBindingDomain: sbd, @@ -228,15 +229,15 @@ var Module = fx.Module("app", } }), - fx.Invoke(func(server *DNSServer, handler *dnsHandler, lf fx.Lifecycle, logger logging.Logger) { + fx.Invoke(func(server *DNSServer, handler *dnsHandler, lf fx.Lifecycle, logger *slog.Logger) { lf.Append(fx.Hook{ OnStart: func(ctx context.Context) error { - logger.Infof("starting dns server at %s", server.Addr) server.Handler = handler go func() { + logger.Info("starting dns server", "at", server.Addr) err := server.ListenAndServe() if err != nil { - logger.Errorf(err, "failed to start dns server") + logger.Error("failed to start dns server, got", "err", err) panic(err) } }() diff --git a/apps/console/internal/app/dns-server.go b/apps/console/internal/app/dns-server.go index 8ad4e94d3..5ad42ef95 100644 --- a/apps/console/internal/app/dns-server.go +++ b/apps/console/internal/app/dns-server.go @@ -3,16 +3,17 @@ package app import ( "context" "fmt" + "log/slog" "strings" + "time" "github.com/kloudlite/api/apps/console/internal/domain" - "github.com/kloudlite/api/pkg/logging" "github.com/kloudlite/operator/pkg/errors" "github.com/miekg/dns" ) type dnsHandler struct { - logger logging.Logger + logger *slog.Logger serviceBindingDomain domain.ServiceBindingDomain kloudliteDNSSuffix string } @@ -22,8 +23,10 @@ const ( ) func (h *dnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { - logger := h.logger.WithKV("query", r.Question[0].Name) - logger.Debugf("incoming dns request") + logger := h.logger.With("query", r.Question[0].Name) + logger.Debug("INCOMING dns request") + start := time.Now() + msg := new(dns.Msg) msg.SetReply(r) msg.Authoritative = true @@ -34,7 +37,7 @@ func (h *dnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { for _, question := range r.Question { answers, err := h.resolver(ctx, question.Name, question.Qtype) if err != nil { - h.logger.Errorf(err) + logger.Error("FAILED to resolve dns record, got", "err", err, "question", question.Name) msg.Rcode = dns.RcodeNameError continue } @@ -42,7 +45,9 @@ func (h *dnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { } w.WriteMsg(msg) - logger.WithKV("answers", msg.Answer).Debugf("outgoing dns request") + if msg.Rcode != dns.RcodeNameError { + logger.Info("RESOLVED dns request", "answers", msg.Answer, "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) + } } func (h *dnsHandler) newRR(domain string, ttl int, ip string) ([]dns.RR, error) { diff --git a/apps/console/internal/app/process-error-on-apply.go b/apps/console/internal/app/process-error-on-apply.go index 22d2bd5de..a1f24eafb 100644 --- a/apps/console/internal/app/process-error-on-apply.go +++ b/apps/console/internal/app/process-error-on-apply.go @@ -4,6 +4,9 @@ import ( "context" "encoding/json" "fmt" + "log/slog" + "sync" + "time" t "github.com/kloudlite/api/apps/tenant-agent/types" "github.com/kloudlite/api/pkg/errors" @@ -13,7 +16,6 @@ import ( "github.com/kloudlite/api/apps/console/internal/entities" msgOfficeT "github.com/kloudlite/api/apps/message-office/types" fn "github.com/kloudlite/api/pkg/functions" - "github.com/kloudlite/api/pkg/logging" "github.com/kloudlite/api/pkg/messaging" msgTypes "github.com/kloudlite/api/pkg/messaging/types" crdsv1 "github.com/kloudlite/operator/apis/crds/v1" @@ -21,9 +23,7 @@ import ( type ErrorOnApplyConsumer messaging.Consumer -func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, d domain.Domain, logger logging.Logger) { - counter := 0 - +func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, d domain.Domain, logger *slog.Logger) { getEnvironmentResourceContext := func(ctx domain.ConsoleContext, resType entities.ResourceType, clusterName string, obj unstructured.Unstructured) (domain.ResourceContext, error) { mapping, err := d.GetEnvironmentResourceMapping(ctx, resType, clusterName, obj.GetNamespace(), obj.GetName()) if err != nil { @@ -35,9 +35,18 @@ func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, d domain.Domain, logger return newResourceContext(ctx, mapping.EnvironmentName), nil } + counter := 0 + mu := sync.Mutex{} + msgReader := func(msg *msgTypes.ConsumeMsg) error { + mu.Lock() counter += 1 - logger.Debugf("received message [%d]", counter) + mu.Unlock() + + start := time.Now() + + logger := logger.With("subject", msg.Subject, "counter", counter) + logger.Debug("INCOMING message", "counter", counter) em, err := msgOfficeT.UnmarshalErrMessage(msg.Payload) if err != nil { @@ -50,25 +59,24 @@ func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, d domain.Domain, logger } obj := unstructured.Unstructured{Object: errObj.Object} + gvkStr := obj.GroupVersionKind().String() - mLogger := logger.WithKV( - "gvk", obj.GroupVersionKind(), - "nn", fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName()), + mlogger := logger.With( + "GVK", gvkStr, + "NN", fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName()), "accountName", em.AccountName, "clusterName", em.ClusterName, ) - mLogger.Infof("received message") + mlogger.Info("validated message") defer func() { - mLogger.Infof("processed message") + mlogger.Info("PROCESSED message", "took", fmt.Sprintf("%.2fs", time.Since(start).Seconds())) }() dctx := domain.NewConsoleContext(context.TODO(), "sys-user:apply-on-error-worker", em.AccountName) opts := domain.UpdateAndDeleteOpts{MessageTimestamp: msg.Timestamp} - gvkStr := obj.GroupVersionKind().String() - switch gvkStr { case environmentGVK.String(): { @@ -204,10 +212,10 @@ func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, d domain.Domain, logger if err := consumer.Consume(msgReader, msgTypes.ConsumeOpts{ OnError: func(err error) error { - logger.Errorf(err, "received while reading messages, ignoring it") + logger.Error("while reading messages, got", "err", err) return nil }, }); err != nil { - logger.Errorf(err, "error while consuming messages") + logger.Error("while consuming messages, got", "err", err) } } diff --git a/apps/console/internal/app/process-resource-updates.go b/apps/console/internal/app/process-resource-updates.go index 306fa32d1..945c9b2d4 100644 --- a/apps/console/internal/app/process-resource-updates.go +++ b/apps/console/internal/app/process-resource-updates.go @@ -4,14 +4,16 @@ import ( "context" "encoding/json" "fmt" + "log/slog" "strings" + "sync" + "time" "github.com/kloudlite/api/apps/console/internal/domain" "github.com/kloudlite/api/apps/console/internal/entities" msgOfficeT "github.com/kloudlite/api/apps/message-office/types" "github.com/kloudlite/api/pkg/errors" fn "github.com/kloudlite/api/pkg/functions" - "github.com/kloudlite/api/pkg/logging" "github.com/kloudlite/api/pkg/messaging" msgTypes "github.com/kloudlite/api/pkg/messaging/types" crdsv1 "github.com/kloudlite/operator/apis/crds/v1" @@ -44,10 +46,8 @@ var ( serviceBindingGVK = fn.GVK("networking.kloudlite.io/v1", "ServiceBinding") ) -func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, logger logging.Logger) { - counter := 0 - - getResourceContext := func(ctx domain.ConsoleContext, rt entities.ResourceType, clusterName string, obj unstructured.Unstructured) (domain.ResourceContext, error) { +func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, logger *slog.Logger) { + getResourceContext := func(ctx domain.ConsoleContext, rt entities.ResourceType, clusterName string, obj *unstructured.Unstructured) (domain.ResourceContext, error) { mapping, err := d.GetEnvironmentResourceMapping(ctx, rt, clusterName, obj.GetNamespace(), obj.GetName()) if err != nil { return domain.ResourceContext{}, err @@ -59,59 +59,66 @@ func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, lo return newResourceContext(ctx, mapping.EnvironmentName), nil } - msgReader := func(msg *msgTypes.ConsumeMsg) error { - logger := logger.WithKV("subject", msg.Subject) + counter := 0 + mu := sync.Mutex{} + msgReader := func(msg *msgTypes.ConsumeMsg) error { + mu.Lock() counter += 1 - logger.Debugf("[%d] received message", counter) + mu.Unlock() + + start := time.Now() + + logger := logger.With("subject", msg.Subject, "counter", counter) + + logger.Debug("INCOMING message") ru, err := msgOfficeT.UnmarshalResourceUpdate(msg.Payload) if err != nil { - logger.Errorf(err, "unmarshaling resource update") + logger.Error("unmarshaling resource update, got", "err", err) return nil } var rwu types.ResourceUpdate if err := json.Unmarshal(ru.WatcherUpdate, &rwu); err != nil { - logger.Errorf(err, "unmarshaling into resource watcher update") + logger.Error("unmarshaling into resource watcher update, got", "err", err) return nil } if rwu.Object == nil { - logger.Infof("msg.Object is nil, so could not extract any info from message, ignoring ...") + logger.Debug("msg.Object is nil, so could not extract any info from message, ignoring ...") return nil } - obj := unstructured.Unstructured{Object: rwu.Object} + obj := rwu.Object + gvkStr := obj.GetObjectKind().GroupVersionKind().String() - mLogger := logger.WithKV( - "gvk", obj.GetObjectKind().GroupVersionKind(), - "resource", fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName()), - "accountName", ru.AccountName, - "clusterName", ru.ClusterName, + mlogger := logger.With( + "GVK", gvkStr, + "NN", fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName()), + "account", ru.AccountName, + "cluster", ru.ClusterName, ) - mLogger.Infof("received message") + mlogger.Debug("validated message") defer func() { - mLogger.Infof("processed message") + mlogger.Info("PROCESSED message", "took", fmt.Sprintf("%dms", time.Since(start).Milliseconds())) }() if len(strings.TrimSpace(ru.AccountName)) == 0 { - logger.Infof("message does not contain 'accountName', so won't be able to find a resource uniquely, thus ignoring ...") + mlogger.Warn("message does not contain 'accountName', so won't be able to find a resource uniquely, thus ignoring ...") return nil } if len(strings.TrimSpace(ru.ClusterName)) == 0 { - logger.Infof("message does not contain 'clusterName', so won't be able to find a resource uniquely, thus ignoring ...") + mlogger.Warn("message does not contain 'clusterName', so won't be able to find a resource uniquely, thus ignoring ...") return nil } dctx := domain.NewConsoleContext(context.TODO(), "sys-user:console-resource-updater", ru.AccountName) - gvkStr := obj.GetObjectKind().GroupVersionKind().String() - resStatus, err := func() (types.ResourceStatus, error) { - v, ok := rwu.Object[types.ResourceStatusKey] + v, ok := obj.Object[types.ResourceStatusKey] if !ok { return "", errors.NewE(fmt.Errorf("field %s not found in object", types.ResourceStatusKey)) } @@ -244,14 +251,13 @@ func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, lo } var outputSecret *corev1.Secret - if v, ok := rwu.Object[types.KeyManagedResSecret]; ok { + if v, ok := obj.Object[types.KeyManagedResSecret]; ok { s, err := fn.JsonConvertP[corev1.Secret](v) if err != nil { - mLogger.Infof("managed resource, invalid output secret received") + mlogger.Error("managed resource, invalid output secret received, got", "err", err) return errors.NewE(err) } s.SetManagedFields(nil) - mLogger.Infof("seting managed resource output secret") outputSecret = s } @@ -281,10 +287,10 @@ func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, lo return errors.NewE(err) } - if v, ok := rwu.Object[types.KeyClusterManagedSvcSecret]; ok { + if v, ok := obj.Object[types.KeyClusterManagedSvcSecret]; ok { v2, err := fn.JsonConvertP[corev1.Secret](v) if err != nil { - mLogger.Infof("managed resource, invalid output secret received") + mlogger.Warn("managed resource, invalid output secret received, got", "err", err) return errors.NewE(err) } v2.SetManagedFields(nil) @@ -302,10 +308,10 @@ func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, lo if err := consumer.Consume(msgReader, msgTypes.ConsumeOpts{ OnError: func(err error) error { - logger.Errorf(err, "received while reading messages, ignoring it") + logger.Error("while reading messages, got", "err", err) return nil }, }); err != nil { - logger.Errorf(err, "error while consuming messages") + logger.Error("while consuming messages, got", "err", err) } } diff --git a/apps/console/internal/domain/domain.go b/apps/console/internal/domain/domain.go index 855af2d0c..7e3fe5be4 100644 --- a/apps/console/internal/domain/domain.go +++ b/apps/console/internal/domain/domain.go @@ -131,7 +131,7 @@ func (d *domain) applyK8sResourceOnCluster(ctx K8sContext, clusterName string, o return errors.NewE(err) } - subject := common.GetTenantClusterMessagingTopic(ctx.GetAccountName(), clusterName) + subject := common.SendToAgentSubjectName(ctx.GetAccountName(), clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()) err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ Subject: subject, @@ -178,7 +178,7 @@ func (d *domain) applyK8sResource(ctx K8sContext, envName string, obj client.Obj return errors.NewE(err) } - subject := common.GetTenantClusterMessagingTopic(ctx.GetAccountName(), *clusterName) + subject := common.SendToAgentSubjectName(ctx.GetAccountName(), *clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()) err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ Subject: subject, @@ -226,7 +226,7 @@ func applyK8sResource(ctx K8sContext, args ApplyK8sResourceArgs) error { return errors.NewE(err) } - subject := common.GetTenantClusterMessagingTopic(ctx.GetAccountName(), args.ClusterName) + subject := common.SendToAgentSubjectName(ctx.GetAccountName(), args.ClusterName, args.Object.GetObjectKind().GroupVersionKind().String(), args.Object.GetNamespace(), args.Object.GetName()) err = args.Dispatcher.Produce(ctx, msgTypes.ProduceMsg{Subject: subject, Payload: b}) return errors.NewE(err) @@ -261,7 +261,7 @@ func (d *domain) restartK8sResource(ctx K8sContext, projectName string, namespac return errors.NewE(err) } - subject := common.GetTenantClusterMessagingTopic(ctx.GetAccountName(), *clusterName) + subject := common.SendToAgentSubjectName(ctx.GetAccountName(), *clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()) err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ Subject: subject, @@ -289,8 +289,9 @@ func (d *domain) deleteK8sResourceOfCluster(ctx K8sContext, clusterName string, return errors.NewE(err) } + subject := common.SendToAgentSubjectName(ctx.GetAccountName(), clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()) err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ - Subject: common.GetTenantClusterMessagingTopic(ctx.GetAccountName(), clusterName), + Subject: subject, Payload: b, }) @@ -326,8 +327,10 @@ func (d *domain) deleteK8sResource(ctx K8sContext, environmentName string, obj c return errors.NewE(err) } + subject := common.SendToAgentSubjectName(ctx.GetAccountName(), *clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()) + err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ - Subject: common.GetTenantClusterMessagingTopic(ctx.GetAccountName(), *clusterName), + Subject: subject, Payload: b, }) diff --git a/apps/console/internal/env/env.go b/apps/console/internal/env/env.go index 6ad55b3e0..1a2bf74f1 100644 --- a/apps/console/internal/env/env.go +++ b/apps/console/internal/env/env.go @@ -18,10 +18,8 @@ type Env struct { AccountCookieName string `env:"ACCOUNT_COOKIE_NAME" required:"true"` ClusterCookieName string `env:"CLUSTER_COOKIE_NAME" required:"true"` - // NATS:start - NatsURL string `env:"NATS_URL" required:"true"` - NatsResourceSyncStream string `env:"NATS_RESOURCE_STREAM" required:"true"` - // NATS:end + NatsURL string `env:"NATS_URL" required:"true"` + NatsReceiveFromAgentStream string `env:"NATS_RECEIVE_FROM_AGENT_STREAM" required:"true"` IAMGrpcAddr string `env:"IAM_GRPC_ADDR" required:"true"` InfraGrpcAddr string `env:"INFRA_GRPC_ADDR" required:"true"` diff --git a/apps/console/internal/framework/framework.go b/apps/console/internal/framework/framework.go index 0f69b5b74..29c707a23 100644 --- a/apps/console/internal/framework/framework.go +++ b/apps/console/internal/framework/framework.go @@ -3,6 +3,7 @@ package framework import ( "context" "fmt" + "log/slog" "github.com/kloudlite/api/apps/console/internal/domain" "github.com/kloudlite/api/common" @@ -10,7 +11,6 @@ import ( app "github.com/kloudlite/api/apps/console/internal/app" "github.com/kloudlite/api/apps/console/internal/env" - rpc "github.com/kloudlite/api/pkg/grpc" httpServer "github.com/kloudlite/api/pkg/http-server" "github.com/kloudlite/api/pkg/k8s" "github.com/kloudlite/api/pkg/kv" @@ -40,7 +40,7 @@ var Module = fx.Module("framework", mongoDb.NewMongoClientFx[*fm](), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.Client, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.Client, error) { return nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: "console", Logger: logger, @@ -69,11 +69,11 @@ var Module = fx.Module("framework", }), fx.Provide(func(ev *env.Env) (app.IAMGrpcClient, error) { - return rpc.NewGrpcClient(ev.IAMGrpcAddr) + return grpc.NewGrpcClient(ev.IAMGrpcAddr) }), fx.Provide(func(ev *env.Env) (app.InfraClient, error) { - return rpc.NewGrpcClient(ev.InfraGrpcAddr) + return grpc.NewGrpcClient(ev.InfraGrpcAddr) }), fx.Invoke(func(lf fx.Lifecycle, c1 app.IAMGrpcClient, c2 app.InfraClient) { @@ -136,7 +136,6 @@ var Module = fx.Module("framework", Server: &dns.Server{ Addr: ev.DNSAddr, Net: "udp", - // Handler: handler, UDPSize: 0xffff, ReusePort: true, }, diff --git a/apps/console/main.go b/apps/console/main.go index 88c40b496..d70cf275f 100644 --- a/apps/console/main.go +++ b/apps/console/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "log/slog" "os" "strings" "time" @@ -22,6 +23,9 @@ import ( func main() { var isDev bool flag.BoolVar(&isDev, "dev", false, "--dev") + + var debug bool + flag.BoolVar(&debug, "debug", false, "--debug") flag.Parse() logger, err := logging.New(&logging.Options{Name: "console", ShowDebugLog: isDev || strings.ToLower(os.Getenv("LOG_LEVEL")) == "debug"}) @@ -36,6 +40,10 @@ func main() { return logger }), + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ShowCaller: true, ShowDebugLogs: debug, SetDefaultLogger: true}) + }), + fx.Provide(func() (*env.Env, error) { if e, err := env.LoadEnv(); err != nil { return nil, errors.NewE(err) diff --git a/common/kafka-topic-name.go b/common/kafka-topic-name.go index 33616f279..53c3ab1b4 100644 --- a/common/kafka-topic-name.go +++ b/common/kafka-topic-name.go @@ -14,16 +14,16 @@ const ( ) const ( - SendToAgentSubjectNamePrefix = "send-to-agent" - ReceiveFromAgentSubjectNamePrefix = "receive-from-agent" + sendToAgentSubjectPrefix = "send-to-agent" + receiveFromAgentSubjectPrefix = "receive-from-agent" ) func SendToAgentSubjectPrefix(accountName string, clusterName string) string { - return fmt.Sprintf("%s.%s.%s", SendToAgentSubjectNamePrefix, accountName, clusterName) + return fmt.Sprintf("%s.%s.%s", sendToAgentSubjectPrefix, accountName, clusterName) } func ReceiveFromAgentSubjectPrefix(accountName string, clusterName string) string { - return fmt.Sprintf("%s.%s.%s", ReceiveFromAgentSubjectNamePrefix, accountName, clusterName) + return fmt.Sprintf("%s.%s.%s", receiveFromAgentSubjectPrefix, accountName, clusterName) } // func GetKafkaTopicName(accountName string, clusterName string) string { @@ -36,9 +36,9 @@ func ReceiveFromAgentSubjectPrefix(accountName string, clusterName string) strin // } func SendToAgentSubjectName(accountName string, clusterName string, gvk string, namespace string, name string) string { - slug := base64.RawStdEncoding.EncodeToString([]byte(fmt.Sprintf("%s.%s/%s", gvk, namespace, name))) + slug := base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf("%s.%s/%s", gvk, namespace, name))) - return fmt.Sprintf("%s.%s.%s.%s", SendToAgentSubjectNamePrefix, accountName, clusterName, slug) + return fmt.Sprintf("%s.%s.%s.%s", sendToAgentSubjectPrefix, accountName, clusterName, slug) } type platformEvent string @@ -59,11 +59,20 @@ const ( type ReceiveFromAgentArgs struct { AccountName string ClusterName string + + GVK string + Namespace string + Name string } func ReceiveFromAgentSubjectName(args ReceiveFromAgentArgs, receiver MessageReceiver, ev platformEvent) string { - slug := "*" - return fmt.Sprintf("%s.%s.%s.%s.%s.%s", ReceiveFromAgentSubjectNamePrefix, args.AccountName, args.ClusterName, slug, receiver, ev) + if args.AccountName == "*" && args.ClusterName == "*" { + slug := "*" + return fmt.Sprintf("%s.%s.%s.%s.%s.%s", receiveFromAgentSubjectPrefix, args.AccountName, args.ClusterName, slug, receiver, ev) + } + + slug := base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf("%s.%s/%s", args.GVK, args.Namespace, args.Name))) + return fmt.Sprintf("%s.%s.%s.%s.%s.%s", receiveFromAgentSubjectPrefix, args.AccountName, args.ClusterName, slug, receiver, ev) } // func GetPlatformClusterMessagingTopic(accountName string, clusterName string, controller messageReceiver, ev platformEvent) string { From a955e5db0754b21804445fbaa3830b9a4afdc881 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 25 Jul 2024 18:54:09 +0530 Subject: [PATCH 8/9] fix(infra): nats subject change, and logging improvements --- .tools/nvim/__http__/console/apps.graphql.yml | 13 +-- .../internal/app/process-resource-updates.go | 14 +-- apps/infra/internal/app/app.go | 9 +- .../internal/app/process-error-on-apply.go | 44 +++++++-- .../internal/app/process-resource-updates.go | 98 ++++++++++--------- apps/infra/internal/domain/byok-clusters.go | 2 +- apps/infra/internal/domain/clusters.go | 69 +++++++------ apps/infra/internal/env/env.go | 2 +- apps/infra/internal/framework/framework.go | 3 +- apps/infra/main.go | 13 +++ apps/tenant-agent/types/types.go | 4 +- 11 files changed, 154 insertions(+), 117 deletions(-) diff --git a/.tools/nvim/__http__/console/apps.graphql.yml b/.tools/nvim/__http__/console/apps.graphql.yml index 6a9110f50..c94e2da84 100644 --- a/.tools/nvim/__http__/console/apps.graphql.yml +++ b/.tools/nvim/__http__/console/apps.graphql.yml @@ -73,21 +73,10 @@ label: Create App query: |+ #graphql mutation Core_createApp($envName: String!, $app: AppIn!) { core_createApp(envName: $envName, app: $app) { + id metadata { name } - syncStatus { - state - recordVersion - error - action - lastSyncedAt - } - createdBy{ - userId - userName - userEmail - } } } variables: diff --git a/apps/console/internal/app/process-resource-updates.go b/apps/console/internal/app/process-resource-updates.go index 945c9b2d4..c337c1073 100644 --- a/apps/console/internal/app/process-resource-updates.go +++ b/apps/console/internal/app/process-resource-updates.go @@ -81,12 +81,12 @@ func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, lo var rwu types.ResourceUpdate if err := json.Unmarshal(ru.WatcherUpdate, &rwu); err != nil { - logger.Error("unmarshaling into resource watcher update, got", "err", err) + logger.Error("unmarshaling into resource update, got", "err", err) return nil } if rwu.Object == nil { - logger.Debug("msg.Object is nil, so could not extract any info from message, ignoring ...") + logger.Debug("msg.object is nil, so could not extract any info from message, ignoring ...") return nil } @@ -100,11 +100,6 @@ func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, lo "cluster", ru.ClusterName, ) - mlogger.Debug("validated message") - defer func() { - mlogger.Info("PROCESSED message", "took", fmt.Sprintf("%dms", time.Since(start).Milliseconds())) - }() - if len(strings.TrimSpace(ru.AccountName)) == 0 { mlogger.Warn("message does not contain 'accountName', so won't be able to find a resource uniquely, thus ignoring ...") return nil @@ -115,6 +110,11 @@ func ProcessResourceUpdates(consumer ResourceUpdateConsumer, d domain.Domain, lo return nil } + mlogger.Debug("validated message") + defer func() { + mlogger.Info("PROCESSED message", "took", fmt.Sprintf("%dms", time.Since(start).Milliseconds())) + }() + dctx := domain.NewConsoleContext(context.TODO(), "sys-user:console-resource-updater", ru.AccountName) resStatus, err := func() (types.ResourceStatus, error) { diff --git a/apps/infra/internal/app/app.go b/apps/infra/internal/app/app.go index 6aa372f7a..b9a405537 100644 --- a/apps/infra/internal/app/app.go +++ b/apps/infra/internal/app/app.go @@ -2,6 +2,7 @@ package app import ( "context" + "log/slog" "github.com/kloudlite/api/grpc-interfaces/kloudlite.io/rpc/console" @@ -126,7 +127,7 @@ var Module = fx.Module( consumerName := "infra:resource-updates" return msg_nats.NewJetstreamConsumer(context.TODO(), jsc, msg_nats.JetstreamConsumerArgs{ - Stream: ev.NatsStream, + Stream: ev.NatsReceiveFromAgentStream, ConsumerConfig: msg_nats.ConsumerConfig{ Name: consumerName, Durable: consumerName, @@ -136,7 +137,7 @@ var Module = fx.Module( }) }), - fx.Invoke(func(lf fx.Lifecycle, consumer ReceiveResourceUpdatesConsumer, d domain.Domain, logger logging.Logger) { + fx.Invoke(func(lf fx.Lifecycle, consumer ReceiveResourceUpdatesConsumer, d domain.Domain, logger *slog.Logger) { lf.Append(fx.Hook{ OnStart: func(context.Context) error { go processResourceUpdates(consumer, d, logger) @@ -154,7 +155,7 @@ var Module = fx.Module( consumerName := "infra:error-on-apply" return msg_nats.NewJetstreamConsumer(context.TODO(), jsc, msg_nats.JetstreamConsumerArgs{ - Stream: ev.NatsStream, + Stream: ev.NatsReceiveFromAgentStream, ConsumerConfig: msg_nats.ConsumerConfig{ Name: consumerName, Durable: consumerName, @@ -164,7 +165,7 @@ var Module = fx.Module( }) }), - fx.Invoke(func(lf fx.Lifecycle, consumer ErrorOnApplyConsumer, d domain.Domain, logger logging.Logger) { + fx.Invoke(func(lf fx.Lifecycle, consumer ErrorOnApplyConsumer, d domain.Domain, logger *slog.Logger) { lf.Append(fx.Hook{ OnStart: func(context.Context) error { go ProcessErrorOnApply(consumer, logger, d) diff --git a/apps/infra/internal/app/process-error-on-apply.go b/apps/infra/internal/app/process-error-on-apply.go index 9e889cb26..43d85a050 100644 --- a/apps/infra/internal/app/process-error-on-apply.go +++ b/apps/infra/internal/app/process-error-on-apply.go @@ -3,6 +3,11 @@ package app import ( "context" "encoding/json" + "fmt" + "log/slog" + "strings" + "sync" + "time" "github.com/kloudlite/api/apps/infra/internal/domain" "github.com/kloudlite/api/apps/infra/internal/entities" @@ -10,7 +15,6 @@ import ( t "github.com/kloudlite/api/apps/tenant-agent/types" "github.com/kloudlite/api/pkg/errors" fn "github.com/kloudlite/api/pkg/functions" - "github.com/kloudlite/api/pkg/logging" "github.com/kloudlite/api/pkg/messaging" "github.com/kloudlite/api/pkg/messaging/types" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -18,10 +22,19 @@ import ( type ErrorOnApplyConsumer messaging.Consumer -func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, logger logging.Logger, d domain.Domain) { +func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, logger *slog.Logger, d domain.Domain) { counter := 0 + mu := sync.Mutex{} + processMsg := func(msg *types.ConsumeMsg) error { + mu.Lock() counter += 1 + mu.Unlock() + + start := time.Now() + + logger := logger.With("subject", msg.Subject, "counter", counter) + logger.Debug("INCOMING message") em, err := msgOfficeT.UnmarshalErrMessage(msg.Payload) if err != nil { @@ -34,16 +47,28 @@ func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, logger logging.Logger, d } obj := unstructured.Unstructured{Object: errObj.Object} + gvkStr := obj.GetObjectKind().GroupVersionKind().String() - mLogger := logger.WithKV( - "gvk", obj.GroupVersionKind(), - "accountName", em.AccountName, - "clusterName", em.ClusterName, + mlogger := logger.With( + "GVK", gvkStr, + "NN", fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName()), + "account", errObj.AccountName, + "cluster", errObj.ClusterName, ) - mLogger.Infof("[%d] received message", counter) + if len(strings.TrimSpace(errObj.AccountName)) == 0 { + mlogger.Warn("message does not contain 'accountName', so won't be able to find a resource uniquely, thus ignoring ...") + return nil + } + + if len(strings.TrimSpace(errObj.ClusterName)) == 0 { + mlogger.Warn("message does not contain 'clusterName', so won't be able to find a resource uniquely, thus ignoring ...") + return nil + } + + mlogger.Debug("validated message") defer func() { - mLogger.Infof("[%d] processed message", counter) + mlogger.Info("PROCESSED message", "took", fmt.Sprintf("%dms", time.Since(start).Milliseconds())) }() dctx := domain.InfraContext{ @@ -103,9 +128,10 @@ func ProcessErrorOnApply(consumer ErrorOnApplyConsumer, logger logging.Logger, d if err := consumer.Consume(processMsg, types.ConsumeOpts{ OnError: func(err error) error { + logger.Error("while reading messages, got", "err", err) return nil }, }); err != nil { - logger.Errorf(err, "when setting up error-on-apply consumer") + logger.Error("when setting up error-on-apply consumer, got", "err", err) } } diff --git a/apps/infra/internal/app/process-resource-updates.go b/apps/infra/internal/app/process-resource-updates.go index 2363ac206..351d40abd 100644 --- a/apps/infra/internal/app/process-resource-updates.go +++ b/apps/infra/internal/app/process-resource-updates.go @@ -4,7 +4,9 @@ import ( "context" "encoding/json" "fmt" + "log/slog" "strings" + "sync" "time" "github.com/kloudlite/api/pkg/errors" @@ -12,9 +14,7 @@ import ( "github.com/kloudlite/api/apps/infra/internal/domain" "github.com/kloudlite/api/apps/infra/internal/entities" fn "github.com/kloudlite/api/pkg/functions" - "github.com/kloudlite/api/pkg/logging" "github.com/kloudlite/operator/operators/resource-watcher/types" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/kloudlite/api/pkg/messaging" msgTypes "github.com/kloudlite/api/pkg/messaging/types" @@ -47,39 +47,76 @@ var ( secretGVK = fn.GVK("v1", "Secret") ) -func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Domain, logger logging.Logger) { +func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Domain, logger *slog.Logger) { + counter := 0 + mu := sync.Mutex{} + readMsg := func(msg *msgTypes.ConsumeMsg) error { - logger.Debugf("processing msg timestamp %s", msg.Timestamp.Format(time.RFC3339)) + mu.Lock() + counter += 1 + mu.Unlock() + + start := time.Now() + + logger := logger.With("subject", msg.Subject, "counter", counter) + logger.Debug("INCOMING message") ru, err := msgOfficeT.UnmarshalResourceUpdate(msg.Payload) if err != nil { - logger.Errorf(err, "unmarshaling resource update") + logger.Error("unmarshaling resource update, got", "err", err) return nil } var su types.ResourceUpdate if err := json.Unmarshal(ru.WatcherUpdate, &su); err != nil { - logger.Errorf(err, "parsing into status update") + logger.Error("unmarshaling into resource update, got", "err", err) return nil } if su.Object == nil { - logger.Infof("message does not contain 'object', so won't be able to find a resource uniquely, thus ignoring ...") + logger.Debug("msg.object is nil, so could not extract any info from message, ignoring ...") return nil } if len(strings.TrimSpace(ru.AccountName)) == 0 { - logger.Infof("message does not contain 'accountName', so won't be able to find a resource uniquely, thus ignoring ...") + logger.Debug("message does not contain 'accountName', so won't be able to find a resource uniquely, thus ignoring ...") + return nil + } + + if len(strings.TrimSpace(ru.ClusterName)) == 0 { + logger.Debug("message does not contain 'clusterName', so won't be able to find a resource uniquely, thus ignoring ...") return nil } dctx := domain.InfraContext{Context: context.TODO(), UserId: "sys-user-process-infra-updates", AccountName: ru.AccountName} - obj := unstructured.Unstructured{Object: su.Object} + obj := su.Object gvkStr := obj.GetObjectKind().GroupVersionKind().String() + mlogger := logger.With( + "GVK", gvkStr, + "NN", fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName()), + "account", ru.AccountName, + "cluster", ru.ClusterName, + ) + + if len(strings.TrimSpace(ru.AccountName)) == 0 { + mlogger.Warn("message does not contain 'accountName', so won't be able to find a resource uniquely, thus ignoring ...") + return nil + } + + if len(strings.TrimSpace(ru.ClusterName)) == 0 { + mlogger.Warn("message does not contain 'clusterName', so won't be able to find a resource uniquely, thus ignoring ...") + return nil + } + + mlogger.Debug("validated message") + defer func() { + mlogger.Info("PROCESSED message", "took", fmt.Sprintf("%dms", time.Since(start).Milliseconds())) + }() + resStatus, err := func() (types.ResourceStatus, error) { - v, ok := su.Object[types.ResourceStatusKey] + v, ok := su.Object.Object[types.ResourceStatusKey] if !ok { return "", errors.NewE(fmt.Errorf("field %s not found in object", types.ResourceStatusKey)) } @@ -94,18 +131,6 @@ func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Do return err } - mLogger := logger.WithKV( - "gvk", obj.GetObjectKind().GroupVersionKind(), - "NN", fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName()), - "resource-status", resStatus, - "accountName/clusterName", fmt.Sprintf("%s/%s", ru.AccountName, ru.ClusterName), - ) - - mLogger.Infof("received message") - defer func() { - mLogger.Infof("processed message") - }() - switch gvkStr { case clusterGVK.String(): { @@ -119,26 +144,6 @@ func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Do } return d.OnClusterUpdateMessage(dctx, clus, resStatus, domain.UpdateAndDeleteOpts{MessageTimestamp: msg.Timestamp}) } - // case globalVpnGVK.String(): - // { - // var gvpn entities.GlobalVPNConnection - // if err := fn.JsonConversion(su.Object, &gvpn); err != nil { - // return errors.NewE(err) - // } - // - // if v, ok := su.Object[types.KeyGlobalVPNWgParams]; ok { - // wp, err := fn.JsonConvertP[wgv1.WgParams](v) - // if err != nil { - // return errors.NewE(err) - // } - // gvpn.ParsedWgParams = wp - // } - // - // if resStatus == types.ResourceStatusDeleted { - // return d.OnGlobalVPNConnectionDeleteMessage(dctx, ru.ClusterName, gvpn) - // } - // return d.OnGlobalVPNConnectionUpdateMessage(dctx, ru.ClusterName, gvpn, resStatus, domain.UpdateAndDeleteOpts{MessageTimestamp: msg.Timestamp}) - // } case gatewayGVK.String(): { var gvpn entities.GlobalVPNConnection @@ -146,7 +151,7 @@ func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Do return errors.NewE(err) } - if v, ok := su.Object[types.KeyGatewayWgParams]; ok { + if v, ok := obj.Object[types.KeyGatewayWgParams]; ok { wp, err := fn.JsonConvertP[networkingv1.WireguardKeys](v) if err != nil { return errors.NewE(err) @@ -238,7 +243,6 @@ func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Do return d.OnNamespaceUpdateMessage(dctx, ru.ClusterName, ns, resStatus, domain.UpdateAndDeleteOpts{MessageTimestamp: msg.Timestamp}) } - case ingressGVK.String(): { var ingress networkv1.Ingress @@ -271,7 +275,7 @@ func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Do } default: { - mLogger.Infof("infra status updates consumer does not acknowledge the gvk %s", gvk(&obj)) + mlogger.Warn("infra resource updates consumer does not acknowledge resource") return nil } } @@ -279,10 +283,10 @@ func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Do if err := consumer.Consume(readMsg, msgTypes.ConsumeOpts{ OnError: func(err error) error { - logger.Errorf(err, "error while consuming message") + logger.Error("while reading messages, got", "err", err) return nil }, }); err != nil { - logger.Errorf(err, "error while consuming messages") + logger.Error("while consuming messages, got", "err", err) } } diff --git a/apps/infra/internal/domain/byok-clusters.go b/apps/infra/internal/domain/byok-clusters.go index 2005e60af..32383757e 100644 --- a/apps/infra/internal/domain/byok-clusters.go +++ b/apps/infra/internal/domain/byok-clusters.go @@ -80,7 +80,7 @@ func (d *domain) CreateBYOKCluster(ctx InfraContext, cluster entities.BYOKCluste cluster.ClusterToken = ctoken - cluster.MessageQueueTopicName = common.GetTenantClusterMessagingTopic(ctx.AccountName, cluster.Name) + cluster.MessageQueueTopicName = common.SendToAgentSubjectPrefix(ctx.AccountName, cluster.Name) gvpnConn, err := d.ensureGlobalVPNConnection(ctx, cluster.Name, cluster.GlobalVPN) if err != nil { diff --git a/apps/infra/internal/domain/clusters.go b/apps/infra/internal/domain/clusters.go index 41b6ef710..51cac2548 100644 --- a/apps/infra/internal/domain/clusters.go +++ b/apps/infra/internal/domain/clusters.go @@ -325,7 +325,7 @@ func (d *domain) CreateCluster(ctx InfraContext, cluster entities.Cluster) (*ent }, } }(), - MessageQueueTopicName: common.GetTenantClusterMessagingTopic(ctx.AccountName, cluster.Name), + MessageQueueTopicName: common.SendToAgentSubjectPrefix(ctx.AccountName, cluster.Name), KloudliteRelease: d.env.KloudliteRelease, Output: nil, } @@ -376,10 +376,10 @@ func (d *domain) CreateCluster(ctx InfraContext, cluster entities.Cluster) (*ent } func (d *domain) syncKloudliteGatewayDevice(ctx InfraContext, gvpnName string) error { - t := time.Now() - defer func() { - d.logger.Infof("syncKloudliteGatewayDevice took %.2fs", time.Since(t).Seconds()) - }() + t := time.Now() + defer func() { + d.logger.Infof("syncKloudliteGatewayDevice took %.2fs", time.Since(t).Seconds()) + }() // 1. parse deployment template b, err := templates.Read(templates.GlobalVPNKloudliteDeviceTemplate) if err != nil { @@ -427,9 +427,9 @@ func (d *domain) syncKloudliteGatewayDevice(ctx InfraContext, gvpnName string) e publicPeers := make([]wgutils.PublicPeer, 0, len(wgParams.PublicPeers)) for _, p := range wgParams.PublicPeers { - if p.PublicKey != clDevice.PublicKey { - publicPeers = append(publicPeers, p) - } + if p.PublicKey != clDevice.PublicKey { + publicPeers = append(publicPeers, p) + } } deviceSvcHosts := make([]string, 0, len(deviceHosts)) @@ -437,7 +437,7 @@ func (d *domain) syncKloudliteGatewayDevice(ctx InfraContext, gvpnName string) e deviceSvcHosts = append(deviceSvcHosts, fmt.Sprintf("%s=%s", k, v)) } - wgParams.PublicPeers = publicPeers + wgParams.PublicPeers = publicPeers wgParams.DNS = klDevice.IPAddr wgParams.ListenPort = 31820 @@ -533,17 +533,17 @@ func (d *domain) syncKloudliteGatewayDevice(ctx InfraContext, gvpnName string) e } deploymentBytes, err := templates.ParseBytes(b, templates.GVPNKloudliteDeviceTemplateVars{ - Name: resourceName, - Namespace: accNs, - WgConfig: wgConfig, + Name: resourceName, + Namespace: accNs, + WgConfig: wgConfig, EnableKubeReverseProxy: false, - KubeReverseProxyImage: d.env.GlobalVPNKubeReverseProxyImage, - AuthzToken: d.env.GlobalVPNKubeReverseProxyAuthzToken, - GatewayDNSServers: strings.Join(dnsServerArgs, ","), - GatewayServiceHosts: strings.Join(deviceSvcHosts, ","), - WireguardPort: wgParams.ListenPort, + KubeReverseProxyImage: d.env.GlobalVPNKubeReverseProxyImage, + AuthzToken: d.env.GlobalVPNKubeReverseProxyAuthzToken, + GatewayDNSServers: strings.Join(dnsServerArgs, ","), + GatewayServiceHosts: strings.Join(deviceSvcHosts, ","), + WireguardPort: wgParams.ListenPort, - KloudliteAccount: gv.AccountName, + KloudliteAccount: gv.AccountName, }) if err != nil { return err @@ -598,7 +598,6 @@ func (d *domain) syncKloudliteDeviceOnPlatform(ctx InfraContext, gvpnName string return err } - wgParams, deviceHosts, err := d.buildGlobalVPNDeviceWgBaseParams(ctx, gvpnConns, clDevice) if err != nil { return err @@ -611,9 +610,9 @@ func (d *domain) syncKloudliteDeviceOnPlatform(ctx InfraContext, gvpnName string publicPeers := make([]wgutils.PublicPeer, 0, len(wgParams.PublicPeers)) for _, p := range wgParams.PublicPeers { - if p.PublicKey != klDevice.PublicKey { - publicPeers = append(publicPeers, p) - } + if p.PublicKey != klDevice.PublicKey { + publicPeers = append(publicPeers, p) + } } deviceSvcHosts := make([]string, 0, len(deviceHosts)) @@ -621,7 +620,7 @@ func (d *domain) syncKloudliteDeviceOnPlatform(ctx InfraContext, gvpnName string deviceSvcHosts = append(deviceSvcHosts, fmt.Sprintf("%s=%s", k, v)) } - wgParams.PublicPeers = publicPeers + wgParams.PublicPeers = publicPeers wgParams.DNS = clDevice.IPAddr wgParams.ListenPort = 31820 @@ -689,17 +688,17 @@ func (d *domain) syncKloudliteDeviceOnPlatform(ctx InfraContext, gvpnName string } deploymentBytes, err := templates.ParseBytes(b, templates.GVPNKloudliteDeviceTemplateVars{ - Name: resourceName, - Namespace: accNs, - WgConfig: wgConfig, + Name: resourceName, + Namespace: accNs, + WgConfig: wgConfig, EnableKubeReverseProxy: true, - KubeReverseProxyImage: d.env.GlobalVPNKubeReverseProxyImage, - AuthzToken: d.env.GlobalVPNKubeReverseProxyAuthzToken, - GatewayDNSServers: strings.Join(dnsServerArgs, ","), - GatewayServiceHosts: strings.Join(deviceSvcHosts, ","), - WireguardPort: wgParams.ListenPort, + KubeReverseProxyImage: d.env.GlobalVPNKubeReverseProxyImage, + AuthzToken: d.env.GlobalVPNKubeReverseProxyAuthzToken, + GatewayDNSServers: strings.Join(dnsServerArgs, ","), + GatewayServiceHosts: strings.Join(deviceSvcHosts, ","), + WireguardPort: wgParams.ListenPort, - KloudliteAccount: gv.AccountName, + KloudliteAccount: gv.AccountName, }) if err != nil { return err @@ -1078,6 +1077,9 @@ func (d *domain) MarkClusterOnlineAt(ctx InfraContext, clusterName string, times if _, err := d.byokClusterRepo.Patch(ctx, entities.UniqueBYOKClusterFilter(ctx.AccountName, clusterName), repos.Document{ fc.BYOKClusterLastOnlineAt: timestamp, }); err != nil { + if errors.Is(err, repos.ErrNoDocuments) { + return nil + } return errors.NewEf(err, "failed to patch last online time for byok cluster %q,", clusterName) } return nil @@ -1089,6 +1091,9 @@ func (d *domain) MarkClusterOnlineAt(ctx InfraContext, clusterName string, times }, repos.Document{ fc.ClusterLastOnlineAt: timestamp, }); err != nil { + if errors.Is(err, repos.ErrNoDocuments) { + return nil + } return errors.NewEf(err, "failed to patch last online time for cluster %q", clusterName) } diff --git a/apps/infra/internal/env/env.go b/apps/infra/internal/env/env.go index 28d8464c2..d88ecc4a0 100644 --- a/apps/infra/internal/env/env.go +++ b/apps/infra/internal/env/env.go @@ -20,7 +20,7 @@ type Env struct { KloudliteDNSSuffix string `env:"KLOUDLITE_DNS_SUFFIX" required:"true"` NatsURL string `env:"NATS_URL" required:"true"` - NatsStream string `env:"NATS_STREAM" required:"true"` + NatsReceiveFromAgentStream string `env:"NATS_RECEIVE_FROM_AGENT_STREAM" required:"true"` AccountCookieName string `env:"ACCOUNT_COOKIE_NAME" required:"true"` ProviderSecretNamespace string `env:"PROVIDER_SECRET_NAMESPACE" required:"true"` diff --git a/apps/infra/internal/framework/framework.go b/apps/infra/internal/framework/framework.go index 48bfe20a5..38ca29653 100644 --- a/apps/infra/internal/framework/framework.go +++ b/apps/infra/internal/framework/framework.go @@ -3,6 +3,7 @@ package framework import ( "context" "fmt" + "log/slog" "github.com/kloudlite/api/apps/infra/internal/app" "github.com/kloudlite/api/apps/infra/internal/env" @@ -41,7 +42,7 @@ var Module = fx.Module("framework", mongoRepo.NewMongoClientFx[*framework](), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.Client, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.Client, error) { return nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: "infra", Logger: logger, diff --git a/apps/infra/main.go b/apps/infra/main.go index e945dc663..8f870c166 100644 --- a/apps/infra/main.go +++ b/apps/infra/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "log/slog" "os" "time" @@ -26,6 +27,10 @@ import ( func main() { var isDev bool flag.BoolVar(&isDev, "dev", false, "--dev") + + var debug bool + flag.BoolVar(&debug, "debug", false, "--debug") + flag.Parse() logger, err := logging.New(&logging.Options{Name: "infra", Dev: isDev}) @@ -40,6 +45,14 @@ func main() { return logger }), + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: debug, + SetAsDefaultLogger: true, + }) + }), + fx.Provide(func() (*env.Env, error) { e, err := env.LoadEnv() if err != nil { diff --git a/apps/tenant-agent/types/types.go b/apps/tenant-agent/types/types.go index 5415b8810..c0a3b2855 100644 --- a/apps/tenant-agent/types/types.go +++ b/apps/tenant-agent/types/types.go @@ -12,8 +12,7 @@ type AgentMessage struct { AccountName string `json:"accountName"` ClusterName string `json:"clusterName"` - Action Action `json:"action"` - // Yamls []byte `json:"yamls,omitempty"` + Action Action `json:"action"` Object map[string]any `json:"object"` } @@ -24,5 +23,4 @@ type AgentErrMessage struct { Error string `json:"error"` Action Action `json:"action"` Object map[string]any `json:"object"` - // Yamls []byte `json:"yamls"` } From 2d0684f56fcd7a7dafcac5f031dc8c09c2ab4280 Mon Sep 17 00:00:00 2001 From: nxtcoder17 Date: Thu, 25 Jul 2024 19:00:30 +0530 Subject: [PATCH 9/9] security: addresses dependabot alters - [Session Middleware Token Injection Vulnerability](https://github.com/kloudlite/api/security/dependabot/31) - [go-retryablehttp can leak basic auth credentials to log files](https://github.com/kloudlite/api/security/dependabot/32) - [gqlparser denial of service vulnerability via the parserDirectives function](https://github.com/kloudlite/api/security/dependabot/33) --- apps/accounts/internal/framework/framework.go | 6 +- apps/accounts/main.go | 9 ++ apps/auth/internal/framework/main.go | 4 +- apps/auth/main.go | 10 ++ apps/comms/internal/framework/framework.go | 3 +- apps/comms/main.go | 18 +++- apps/console/main.go | 2 +- .../internal/app/adapter-resource-apply.go | 4 +- apps/container-registry/internal/app/main.go | 4 +- .../internal/app/process-resource-updates.go | 7 +- .../internal/framework/framework.go | 3 +- apps/container-registry/main.go | 9 ++ .../internal/framework/framework.go | 3 +- apps/message-office/main.go | 5 +- .../internal/framework/framework.go | 4 +- apps/observability/main.go | 9 ++ apps/webhook/internal/framework/main.go | 4 +- apps/webhook/main.go | 10 ++ .../internal/framework/framework.go | 3 +- apps/websocket-server/main.go | 9 ++ go.mod | 47 ++++---- go.sum | 100 ++++++++---------- 22 files changed, 169 insertions(+), 104 deletions(-) diff --git a/apps/accounts/internal/framework/framework.go b/apps/accounts/internal/framework/framework.go index a3181ca81..866c8ddf7 100644 --- a/apps/accounts/internal/framework/framework.go +++ b/apps/accounts/internal/framework/framework.go @@ -3,10 +3,12 @@ package framework import ( "context" "fmt" + "log/slog" + "time" + "github.com/kloudlite/api/common" "github.com/kloudlite/api/pkg/errors" "github.com/kloudlite/api/pkg/nats" - "time" "github.com/kloudlite/api/pkg/kv" "github.com/kloudlite/api/pkg/repos" @@ -33,7 +35,7 @@ var Module = fx.Module("framework", return &fm{env: ev} }), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.JetstreamClient, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.JetstreamClient, error) { name := "accounts:jetstream-client" nc, err := nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: name, diff --git a/apps/accounts/main.go b/apps/accounts/main.go index 52bd5ca19..9014f4bba 100644 --- a/apps/accounts/main.go +++ b/apps/accounts/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "log/slog" "os" "time" @@ -35,6 +36,14 @@ func main() { return logger }), + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: isDev, + SetAsDefaultLogger: true, + }) + }), + fx.Provide(func() (*env.Env, error) { if e, err := env.LoadEnv(); err != nil { return nil, errors.NewE(err) diff --git a/apps/auth/internal/framework/main.go b/apps/auth/internal/framework/main.go index 9dc3aef1f..449e48b19 100644 --- a/apps/auth/internal/framework/main.go +++ b/apps/auth/internal/framework/main.go @@ -3,6 +3,8 @@ package framework import ( "context" "fmt" + "log/slog" + "github.com/kloudlite/api/common" "github.com/kloudlite/api/pkg/errors" "github.com/kloudlite/api/pkg/kv" @@ -57,7 +59,7 @@ var Module fx.Option = fx.Module( repos.NewMongoClientFx[*fm](), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.JetstreamClient, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.JetstreamClient, error) { name := "auth:jetstream-client" nc, err := nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: name, diff --git a/apps/auth/main.go b/apps/auth/main.go index 99f40d71f..944ed2adc 100644 --- a/apps/auth/main.go +++ b/apps/auth/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "log/slog" "time" "github.com/kloudlite/api/pkg/errors" @@ -36,6 +37,15 @@ func main() { return logging.New(&logging.Options{Name: "auth", Dev: isDev}) }, ), + + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: isDev, + SetAsDefaultLogger: true, + }) + }), + framework.Module, ) diff --git a/apps/comms/internal/framework/framework.go b/apps/comms/internal/framework/framework.go index ccaa1326d..2058bcc86 100644 --- a/apps/comms/internal/framework/framework.go +++ b/apps/comms/internal/framework/framework.go @@ -3,6 +3,7 @@ package framework import ( "context" "fmt" + "log/slog" "time" "github.com/kloudlite/api/apps/comms/internal/app" @@ -35,7 +36,7 @@ var Module = fx.Module( return &fm{ev} }), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.Client, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.Client, error) { return nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: "comms", Logger: logger, diff --git a/apps/comms/main.go b/apps/comms/main.go index b1d880522..4927f97f3 100644 --- a/apps/comms/main.go +++ b/apps/comms/main.go @@ -4,6 +4,7 @@ import ( "context" "embed" "flag" + "log/slog" "os" "time" @@ -30,11 +31,18 @@ func main() { webApp := fx.New( fx.NopLogger, - fx.Provide( - func() logging.Logger { - return logger - }, - ), + fx.Provide(func() logging.Logger { + return logger + }), + + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: isDev, + SetAsDefaultLogger: true, + }) + }), + fx.Provide(func() (*env.Env, error) { return env.LoadEnv() }), diff --git a/apps/console/main.go b/apps/console/main.go index d70cf275f..d655ba441 100644 --- a/apps/console/main.go +++ b/apps/console/main.go @@ -41,7 +41,7 @@ func main() { }), fx.Provide(func() *slog.Logger { - return logging.NewSlogLogger(logging.SlogOptions{ShowCaller: true, ShowDebugLogs: debug, SetDefaultLogger: true}) + return logging.NewSlogLogger(logging.SlogOptions{ShowCaller: true, ShowDebugLogs: debug, SetAsDefaultLogger: true}) }), fx.Provide(func() (*env.Env, error) { diff --git a/apps/container-registry/internal/app/adapter-resource-apply.go b/apps/container-registry/internal/app/adapter-resource-apply.go index a4fa7ce93..e9defdefd 100644 --- a/apps/container-registry/internal/app/adapter-resource-apply.go +++ b/apps/container-registry/internal/app/adapter-resource-apply.go @@ -52,7 +52,7 @@ func (a *resourceDispatcherImpl) ApplyToTargetCluster(ctx domain.RegistryContext } err = a.producer.Produce(ctx, msgTypes.ProduceMsg{ - Subject: common.GetTenantClusterMessagingTopic(ctx.AccountName, clusterName), + Subject: common.SendToAgentSubjectName(ctx.AccountName, clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()), Payload: b, }) @@ -76,7 +76,7 @@ func (d *resourceDispatcherImpl) DeleteFromTargetCluster(ctx domain.RegistryCont } err = d.producer.Produce(ctx, msgTypes.ProduceMsg{ - Subject: common.GetTenantClusterMessagingTopic(ctx.AccountName, clusterName), + Subject: common.SendToAgentSubjectName(ctx.AccountName, clusterName, obj.GetObjectKind().GroupVersionKind().String(), obj.GetNamespace(), obj.GetName()), Payload: b, }) diff --git a/apps/container-registry/internal/app/main.go b/apps/container-registry/internal/app/main.go index 509dc2c44..7fd954841 100644 --- a/apps/container-registry/internal/app/main.go +++ b/apps/container-registry/internal/app/main.go @@ -109,7 +109,7 @@ var Module = fx.Module("app", }), fx.Provide(func(jsc *nats.JetstreamClient, ev *env.Env) (ReceiveResourceUpdatesConsumer, error) { - topic := common.GetPlatformClusterMessagingTopic("*", "*", common.ContainerRegistryReceiver, common.EventResourceUpdate) + topic := common.ReceiveFromAgentSubjectName(common.ReceiveFromAgentArgs{AccountName: "*", ClusterName: "*"}, common.ContainerRegistryReceiver, common.EventResourceUpdate) consumerName := "cr:resource-updates" return msg_nats.NewJetstreamConsumer(context.TODO(), jsc, msg_nats.JetstreamConsumerArgs{ @@ -136,7 +136,7 @@ var Module = fx.Module("app", }), fx.Provide(func(jsc *nats.JetstreamClient, ev *env.Env) (ErrorOnApplyConsumer, error) { - topic := common.GetPlatformClusterMessagingTopic("*", "*", common.ConsoleReceiver, common.EventErrorOnApply) + topic := common.ReceiveFromAgentSubjectName(common.ReceiveFromAgentArgs{AccountName: "*", ClusterName: "*"}, common.ContainerRegistryReceiver, common.EventErrorOnApply) consumerName := "cr:error-on-apply" diff --git a/apps/container-registry/internal/app/process-resource-updates.go b/apps/container-registry/internal/app/process-resource-updates.go index b9a9825be..ee3ae3925 100644 --- a/apps/container-registry/internal/app/process-resource-updates.go +++ b/apps/container-registry/internal/app/process-resource-updates.go @@ -14,7 +14,6 @@ import ( fn "github.com/kloudlite/api/pkg/functions" "github.com/kloudlite/api/pkg/logging" "github.com/kloudlite/operator/operators/resource-watcher/types" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" msgOfficeT "github.com/kloudlite/api/apps/message-office/types" "github.com/kloudlite/api/pkg/messaging" @@ -57,14 +56,14 @@ func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Do return nil } - obj := unstructured.Unstructured{Object: su.Object} + obj := su.Object mLogger := logger.WithKV( "gvk", obj.GetObjectKind().GroupVersionKind(), "accountName/clusterName", fmt.Sprintf("%s/%s", ru.AccountName, ru.ClusterName), ) resStatus, err := func() (types.ResourceStatus, error) { - v, ok := su.Object[types.ResourceStatusKey] + v, ok := obj.Object[types.ResourceStatusKey] if !ok { return "", errors.NewE(fmt.Errorf("field %s not found in object", types.ResourceStatusKey)) } @@ -110,7 +109,7 @@ func processResourceUpdates(consumer ReceiveResourceUpdatesConsumer, d domain.Do default: { - mLogger.Infof("container registry status updates consumer does not acknowledge the gvk %s", gvk(&obj)) + mLogger.Infof("container registry status updates consumer does not acknowledge the gvk %s", gvk(obj)) return nil } } diff --git a/apps/container-registry/internal/framework/framework.go b/apps/container-registry/internal/framework/framework.go index a2f455b0d..b602c0b45 100644 --- a/apps/container-registry/internal/framework/framework.go +++ b/apps/container-registry/internal/framework/framework.go @@ -3,6 +3,7 @@ package framework import ( "context" "fmt" + "log/slog" "time" "github.com/kloudlite/api/common" @@ -49,7 +50,7 @@ var Module = fx.Module("framework", mongoDb.NewMongoClientFx[*fm](), - fx.Provide(func(logger logging.Logger, ev *env.Env) (*nats.Client, error) { + fx.Provide(func(logger *slog.Logger, ev *env.Env) (*nats.Client, error) { name := "cr" return nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: name, diff --git a/apps/container-registry/main.go b/apps/container-registry/main.go index 7049e9651..e9bb338c0 100644 --- a/apps/container-registry/main.go +++ b/apps/container-registry/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "log/slog" "runtime/trace" "github.com/kloudlite/api/apps/container-registry/internal/env" @@ -36,6 +37,14 @@ func main() { }, ), + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: isDev, + SetAsDefaultLogger: true, + }) + }), + fn.FxErrorHandler(), framework.Module, ) diff --git a/apps/message-office/internal/framework/framework.go b/apps/message-office/internal/framework/framework.go index 8ad128beb..74faecb5d 100644 --- a/apps/message-office/internal/framework/framework.go +++ b/apps/message-office/internal/framework/framework.go @@ -3,6 +3,7 @@ package framework import ( "context" "fmt" + "log/slog" "github.com/kloudlite/api/pkg/errors" @@ -39,7 +40,7 @@ var Module = fx.Module("framework", return grpc.NewGrpcClient(f.VectorGrpcAddr) }), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.JetstreamClient, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.JetstreamClient, error) { nc, err := nats.NewClient(ev.NatsUrl, nats.ClientOpts{ Name: "message-offfice", Logger: logger, diff --git a/apps/message-office/main.go b/apps/message-office/main.go index 8b5e8585f..cbc4614d9 100644 --- a/apps/message-office/main.go +++ b/apps/message-office/main.go @@ -46,8 +46,9 @@ func main() { fx.Provide(func() *slog.Logger { return logging.NewSlogLogger(logging.SlogOptions{ - ShowCaller: true, - ShowDebugLogs: debug, + ShowCaller: true, + ShowDebugLogs: debug, + SetAsDefaultLogger: true, }) }), diff --git a/apps/observability/internal/framework/framework.go b/apps/observability/internal/framework/framework.go index d4f77e6d4..9fa487961 100644 --- a/apps/observability/internal/framework/framework.go +++ b/apps/observability/internal/framework/framework.go @@ -3,6 +3,7 @@ package framework import ( "context" "fmt" + "log/slog" "net/http" "github.com/kloudlite/api/apps/observability/internal/app" @@ -10,7 +11,6 @@ import ( "github.com/kloudlite/api/common" "github.com/kloudlite/api/pkg/grpc" "github.com/kloudlite/api/pkg/kv" - "github.com/kloudlite/api/pkg/logging" "github.com/kloudlite/api/pkg/nats" "go.uber.org/fx" ) @@ -24,7 +24,7 @@ var Module = fx.Module("framework", return grpc.NewGrpcClient(ev.InfraGrpcAddr) }), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.Client, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.Client, error) { return nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: "observability-api", Logger: logger, diff --git a/apps/observability/main.go b/apps/observability/main.go index 3140cd0f5..8539637a2 100644 --- a/apps/observability/main.go +++ b/apps/observability/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "log/slog" "os" "time" @@ -41,6 +42,14 @@ func main() { return logger }), + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: isDev, + SetAsDefaultLogger: true, + }) + }), + fx.Provide(func() (*env.Env, error) { if e, err := env.LoadEnv(); err != nil { return nil, errors.NewE(err) diff --git a/apps/webhook/internal/framework/main.go b/apps/webhook/internal/framework/main.go index c5f327261..3dbe45dec 100644 --- a/apps/webhook/internal/framework/main.go +++ b/apps/webhook/internal/framework/main.go @@ -3,6 +3,8 @@ package framework import ( "context" "fmt" + "log/slog" + "github.com/kloudlite/api/apps/webhook/internal/app" "github.com/kloudlite/api/apps/webhook/internal/env" "github.com/kloudlite/api/pkg/errors" @@ -32,7 +34,7 @@ var Module = fx.Module( }, ), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.JetstreamClient, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.JetstreamClient, error) { name := "webhook:jetstream-client" nc, err := nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: name, diff --git a/apps/webhook/main.go b/apps/webhook/main.go index ffb9378b1..d18e0842b 100644 --- a/apps/webhook/main.go +++ b/apps/webhook/main.go @@ -2,6 +2,7 @@ package main import ( "flag" + "log/slog" "github.com/kloudlite/api/apps/webhook/internal/env" "github.com/kloudlite/api/apps/webhook/internal/framework" @@ -22,6 +23,15 @@ func main() { return logging.New(&logging.Options{Name: "webhooks", Dev: isDev}) }, ), + + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: isDev, + SetAsDefaultLogger: true, + }) + }), + fn.FxErrorHandler(), config.EnvFx[env.Env](), framework.Module, diff --git a/apps/websocket-server/internal/framework/framework.go b/apps/websocket-server/internal/framework/framework.go index 334b97239..2e7bbd89c 100644 --- a/apps/websocket-server/internal/framework/framework.go +++ b/apps/websocket-server/internal/framework/framework.go @@ -3,6 +3,7 @@ package framework import ( "context" "fmt" + "log/slog" "github.com/kloudlite/api/common" "github.com/kloudlite/api/pkg/errors" @@ -28,7 +29,7 @@ var Module = fx.Module("framework", return &fm{env: ev} }), - fx.Provide(func(ev *env.Env, logger logging.Logger) (*nats.Client, error) { + fx.Provide(func(ev *env.Env, logger *slog.Logger) (*nats.Client, error) { name := "RUP:nat-client" return nats.NewClient(ev.NatsURL, nats.ClientOpts{ Name: name, diff --git a/apps/websocket-server/main.go b/apps/websocket-server/main.go index 8b8dfae0f..33f96f99a 100644 --- a/apps/websocket-server/main.go +++ b/apps/websocket-server/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "log/slog" "os" "time" @@ -33,6 +34,14 @@ func main() { return logger }), + fx.Provide(func() *slog.Logger { + return logging.NewSlogLogger(logging.SlogOptions{ + ShowCaller: true, + ShowDebugLogs: isDev, + SetAsDefaultLogger: true, + }) + }), + fx.Provide(func() (*env.Env, error) { if e, err := env.LoadEnv(); err != nil { return nil, errors.NewE(err) diff --git a/go.mod b/go.mod index 70abb8efb..291c7ebe9 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/kloudlite/api go 1.21.1 require ( - github.com/99designs/gqlgen v0.17.45 + github.com/99designs/gqlgen v0.17.49 github.com/Masterminds/sprig/v3 v3.2.3 github.com/aws/aws-sdk-go v1.50.10 github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 @@ -11,17 +11,17 @@ require ( github.com/go-redis/redis/v8 v8.11.5 github.com/gobuffalo/flect v1.0.2 github.com/gofiber/adaptor/v2 v2.1.23 - github.com/gofiber/fiber/v2 v2.52.2 + github.com/gofiber/fiber/v2 v2.52.5 github.com/gofiber/websocket/v2 v2.0.21 github.com/google/go-github/v43 v43.0.0 github.com/google/go-github/v45 v45.2.0 github.com/gorilla/websocket v1.5.0 - github.com/kloudlite/operator v0.0.0-20240718072819-c625b77c43b2 + github.com/kloudlite/operator v0.0.0-20240725140628-a3dbbc898710 github.com/matoous/go-nanoid/v2 v2.0.0 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.29.1 github.com/sendgrid/sendgrid-go v3.11.1+incompatible - github.com/vektah/gqlparser/v2 v2.5.11 + github.com/vektah/gqlparser/v2 v2.5.16 github.com/xanzy/go-gitlab v0.63.0 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yext/yerrors v0.0.0-20230716030415-7ebf68e23868 // indirect @@ -29,9 +29,9 @@ require ( go.uber.org/fx v1.17.1 go.uber.org/zap v1.26.0 golang.org/x/oauth2 v0.16.0 - golang.org/x/sync v0.6.0 + golang.org/x/sync v0.7.0 google.golang.org/grpc v1.61.0 - google.golang.org/protobuf v1.33.0 + google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/api v0.28.4 k8s.io/apiextensions-apiserver v0.28.3 @@ -43,6 +43,8 @@ require ( require ( github.com/PaesslerAG/jsonpath v0.1.1 + github.com/charmbracelet/lipgloss v0.10.0 + github.com/charmbracelet/log v0.4.0 github.com/go-chi/chi/v5 v5.0.10 github.com/kloudlite/container-registry-authorizer v0.0.0-20231021122509-161dc30fde55 github.com/miekg/dns v1.1.55 @@ -54,24 +56,21 @@ require ( github.com/stretchr/testify v1.9.0 github.com/ztrue/tracerr v0.4.0 golang.org/x/exp v0.0.0-20231006140011-7918f672742d - golang.org/x/net v0.23.0 + golang.org/x/net v0.27.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 ) require ( github.com/PaesslerAG/gval v1.0.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/lipgloss v0.10.0 // indirect - github.com/charmbracelet/log v0.4.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect - github.com/hashicorp/go-hclog v1.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/muesli/reflow v0.3.0 // indirect @@ -82,7 +81,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/seancfoley/bintree v1.2.1 // indirect - github.com/sosodev/duration v1.2.0 // indirect + github.com/sosodev/duration v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -102,7 +101,7 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/evanphx/json-patch/v5 v5.7.0 // indirect github.com/fasthttp/websocket v1.5.0 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect @@ -120,13 +119,13 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.7 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -146,26 +145,26 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/pflag v1.0.5 - github.com/urfave/cli/v2 v2.27.1 // indirect + github.com/urfave/cli/v2 v2.27.3 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.52.0 // indirect + github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect go.uber.org/dig v1.14.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.19.0 + golang.org/x/tools v0.23.0 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/go.sum b/go.sum index 4637c250f..13efacb0d 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiV cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik= -github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0= +github.com/99designs/gqlgen v0.17.49 h1:b3hNGexHd33fBSAd4NDT/c3NCcQzcAVkknhN9ym36YQ= +github.com/99designs/gqlgen v0.17.49/go.mod h1:tC8YFVZMed81x7UJ7ORUwXF4Kn6SXuucFqQBhN8+BU0= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= @@ -15,8 +15,8 @@ github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk= github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY= -github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= -github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY= +github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE= +github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= @@ -67,9 +67,8 @@ github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0n github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fasthttp/websocket v1.5.0 h1:B4zbe3xXyvIdnqjOZrafVFklCUq5ZLo/TqCt5JA1wLE= github.com/fasthttp/websocket v1.5.0/go.mod h1:n0BlOQvJdPbTuBkZT0O5+jk/sp/1/VCzquR1BehI2F4= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= @@ -99,8 +98,8 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gofiber/adaptor/v2 v2.1.23 h1:VG0yAPnB2EJZjxy4Ul+Ra9e92PnqwXE97SUVuPGuoAA= github.com/gofiber/adaptor/v2 v2.1.23/go.mod h1:hnYEQBPF2x1JaBHygutJJF5d0+J2eYnKKsUMCSsfxKk= github.com/gofiber/fiber/v2 v2.32.0/go.mod h1:CMy5ZLiXkn6qwthrl03YMyW1NLfj0rhxz2LKl4t7ZTY= -github.com/gofiber/fiber/v2 v2.52.2 h1:b0rYH6b06Df+4NyrbdptQL8ifuxw/Tf2DgfkZkDaxEo= -github.com/gofiber/fiber/v2 v2.52.2/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= +github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofiber/utils v0.1.2 h1:1SH2YEz4RlNS0tJlMJ0bGwO0JkqPqvq6TbHK9tXZKtk= github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc= github.com/gofiber/websocket/v2 v2.0.21 h1:mQEiLXBqFsNNlJc5dzFgSGeoqoEXYvIcdBQzAZBdbL0= @@ -150,11 +149,10 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I= -github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= -github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -176,12 +174,12 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.14.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kloudlite/container-registry-authorizer v0.0.0-20231021122509-161dc30fde55 h1:YnZh3TL6AG4EfoInx1/L5zcPHd2QxgLKseJB1KtHjdQ= github.com/kloudlite/container-registry-authorizer v0.0.0-20231021122509-161dc30fde55/go.mod h1:GZj3wZmIw/qCciclRhgQTgmGiqe8wxoVzMXQjbOfnbc= -github.com/kloudlite/operator v0.0.0-20240718072819-c625b77c43b2 h1:K6tlpBcl4PWv6ZiojFTXADYuAvGjcOkrYQbsPvbXaOU= -github.com/kloudlite/operator v0.0.0-20240718072819-c625b77c43b2/go.mod h1:c6FiZvYztvr92/UcIUvQurp3oWMrrEK7deAriHckTPw= +github.com/kloudlite/operator v0.0.0-20240725140628-a3dbbc898710 h1:a+5HIVOce/XVsIGg8JRfaULu9sULJZPp0yDhyBkp3BU= +github.com/kloudlite/operator v0.0.0-20240725140628-a3dbbc898710/go.mod h1:c6FiZvYztvr92/UcIUvQurp3oWMrrEK7deAriHckTPw= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -196,18 +194,16 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U= github.com/matoous/go-nanoid/v2 v2.0.0 h1:d19kur2QuLeHmJBkvYkFdhFBzLoo1XVm2GgTpL+9Tj0= github.com/matoous/go-nanoid/v2 v2.0.0/go.mod h1:FtS4aGPVfEkxKxhdWPAspZpZSh1cOjtM7Ej/So3hR0g= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= @@ -290,8 +286,8 @@ github.com/shamaton/msgpack/v2 v2.2.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naV github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us= -github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4= +github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= @@ -309,23 +305,22 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= -github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.27.3 h1:/POWahRmdh7uztQ3CYnaDddk0Rm90PyOgIxgW2rr41M= +github.com/urfave/cli/v2 v2.27.3/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.33.0/go.mod h1:KJRK/MXx0J+yd0c5hlR+s1tIHD72sniU8ZJjl97LIw4= github.com/valyala/fasthttp v1.35.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0= -github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ= +github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= +github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= -github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= +github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8= +github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww= github.com/xanzy/go-gitlab v0.63.0 h1:a9fXpKWykUS6dowapFej/2Wjf4aOAEFC1q2ZIcz4IpI= github.com/xanzy/go-gitlab v0.63.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -341,8 +336,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yext/yerrors v0.0.0-20230716030415-7ebf68e23868 h1:WHNghr01OczJetcg4v+Znzb1GhGsocXm+bMjRMhRv1c= github.com/yext/yerrors v0.0.0-20230716030415-7ebf68e23868/go.mod h1:zhIgUGzifKsRLyFziQsd8PudAFXXsXaAckJ9+3MojNg= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= @@ -375,15 +370,15 @@ golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -395,8 +390,8 @@ golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= @@ -404,12 +399,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -419,20 +412,19 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -441,8 +433,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -450,8 +442,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -471,8 +463,8 @@ google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=