From efecb8ee0cada4581e4f7a2f2a533d16e710afbd Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Mon, 25 Mar 2024 11:29:56 +0000 Subject: [PATCH] [Maintenance] Extract Debug CLI --- cmd/cmd.go | 48 +++++++++------------- pkg/logging/cli.go | 85 +++++++++++++++++++++++++++++++++++++++ pkg/util/errors/errors.go | 8 ---- 3 files changed, 104 insertions(+), 37 deletions(-) create mode 100644 pkg/logging/cli.go diff --git a/cmd/cmd.go b/cmd/cmd.go index bf85f80dd..116c7108f 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -75,7 +75,6 @@ const ( defaultServerPort = 8528 defaultAPIHTTPPort = 8628 defaultAPIGRPCPort = 8728 - defaultLogLevel = "info" defaultAdminSecretName = "arangodb-operator-dashboard" defaultAPIJWTSecretName = "arangodb-operator-api-jwt" defaultAPIJWTKeySecretName = "arangodb-operator-api-jwt-key" @@ -96,9 +95,6 @@ var ( hardLimit uint64 } - logFormat string - logLevels []string - logSampling bool serverOptions struct { host string port int @@ -195,9 +191,6 @@ func init() { f.StringVar(&serverOptions.tlsSecretName, "server.tls-secret-name", "", "Name of secret containing tls.crt & tls.key for HTTPS server (if empty, self-signed certificate is used)") f.StringVar(&serverOptions.adminSecretName, "server.admin-secret-name", defaultAdminSecretName, "Name of secret containing username + password for login to the dashboard") f.BoolVar(&serverOptions.allowAnonymous, "server.allow-anonymous-access", false, "Allow anonymous access to the dashboard") - f.StringVar(&logFormat, "log.format", "pretty", "Set log format. Allowed values: 'pretty', 'JSON'. If empty, default format is used") - f.StringArrayVar(&logLevels, "log.level", []string{defaultLogLevel}, fmt.Sprintf("Set log levels in format or =. Possible loggers: %s", strings.Join(logging.Global().Names(), ", "))) - f.BoolVar(&logSampling, "log.sampling", true, "If true, operator will try to minimize duplication of logging events") f.BoolVar(&apiOptions.enabled, "api.enabled", true, "Enable operator HTTP and gRPC API") f.IntVar(&apiOptions.httpPort, "api.http-port", defaultAPIHTTPPort, "HTTP API port to listen on") f.IntVar(&apiOptions.grpcPort, "api.grpc-port", defaultAPIGRPCPort, "gRPC API port to listen on") @@ -247,6 +240,9 @@ func init() { f.StringArrayVar(&metricsOptions.excludedMetricPrefixes, "metrics.excluded-prefixes", nil, "List of the excluded metrics prefixes") f.BoolVar(&operatorImageDiscovery.defaultStatusDiscovery, "image.discovery.status", true, "Discover Operator Image from Pod Status by default. When disabled Pod Spec is used.") f.DurationVar(&operatorImageDiscovery.timeout, "image.discovery.timeout", time.Minute, "Timeout for image discovery process") + if err := logging.Init(&cmdMain); err != nil { + panic(err.Error()) + } if err := features.Init(&cmdMain); err != nil { panic(err.Error()) } @@ -308,24 +304,10 @@ func executeMain(cmd *cobra.Command, args []string) { kclient.SetDefaultBurst(operatorKubernetesOptions.burst) // Prepare log service - var err error - - levels, err := logging.ParseLogLevelsFromArgs(logLevels) - if err != nil { - logger.Err(err).Fatal("Unable to parse log level") + if err := logging.Enable(); err != nil { + logger.Err(err).Fatal("Unable to enable logger") } - // Set root logger to stdout (JSON formatted) if not prettified - if strings.ToUpper(logFormat) == "JSON" { - logging.Global().SetRoot(zerolog.New(os.Stdout).With().Timestamp().Logger()) - } else if strings.ToLower(logFormat) != "pretty" && logFormat != "" { - logger.Fatal("Unknown log format: %s", logFormat) - } - logging.Global().Configure(logging.Config{ - Levels: levels, - Sampling: logSampling, - }) - podNameParts := strings.Split(name, "-") operatorID := podNameParts[len(podNameParts)-1] @@ -347,16 +329,16 @@ func executeMain(cmd *cobra.Command, args []string) { !operatorOptions.enableBackup && !operatorOptions.enableApps && !operatorOptions.enableK2KClusterSync && !operatorOptions.enableML { if !operatorOptions.versionOnly { if version.GetVersionV1().IsEnterprise() { - logger.Err(err).Fatal("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.ml or any combination of these") + logger.Fatal("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.ml or any combination of these") } else { - logger.Err(err).Fatal("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync or any combination of these") + logger.Fatal("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync or any combination of these") } } } else if operatorOptions.versionOnly { - logger.Err(err).Fatal("Options --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.ml cannot be enabled together with --operator.version") + logger.Fatal("Options --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.ml cannot be enabled together with --operator.version") } else if !version.GetVersionV1().IsEnterprise() { if operatorOptions.enableML { - logger.Err(err).Fatal("Options --operator.ml can be enabled only on the Enterprise Operator") + logger.Fatal("Options --operator.ml can be enabled only on the Enterprise Operator") } } @@ -444,7 +426,11 @@ func executeMain(cmd *cobra.Command, args []string) { if err != nil { logger.Err(err).Fatal("Failed to create API server") } - go errors.LogError(logger, "while running API server", apiServer.Run) + go func() { + if err := apiServer.Run(); err != nil { + logger.Err(err).Error("while running API server") + } + }() } listenAddr := net.JoinHostPort(serverOptions.host, strconv.Itoa(serverOptions.port)) @@ -493,7 +479,11 @@ func executeMain(cmd *cobra.Command, args []string) { }); err != nil { logger.Err(err).Fatal("Failed to create HTTP server") } else { - go errors.LogError(logger, "error while starting server", svr.Run) + go func() { + if err := svr.Run(); err != nil { + logger.Err(err).Error("error while starting server") + } + }() } // startChaos(context.Background(), cfg.KubeCli, cfg.Namespace, chaosLevel) diff --git a/pkg/logging/cli.go b/pkg/logging/cli.go new file mode 100644 index 000000000..381561b9b --- /dev/null +++ b/pkg/logging/cli.go @@ -0,0 +1,85 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package logging + +import ( + "fmt" + "os" + "strings" + "sync" + + "github.com/rs/zerolog" + "github.com/spf13/cobra" + + "github.com/arangodb/kube-arangodb/pkg/util/errors" +) + +const ( + defaultLogLevel = "info" +) + +var ( + enableLock sync.Mutex + enabled bool + + cli struct { + format string + levels []string + sampling bool + } +) + +func Init(cmd *cobra.Command) error { + f := cmd.PersistentFlags() + + f.StringVar(&cli.format, "log.format", "pretty", "Set log format. Allowed values: 'pretty', 'JSON'. If empty, default format is used") + f.StringArrayVar(&cli.levels, "log.level", []string{defaultLogLevel}, fmt.Sprintf("Set log levels in format or =. Possible loggers: %s", strings.Join(Global().Names(), ", "))) + f.BoolVar(&cli.sampling, "log.sampling", true, "If true, operator will try to minimize duplication of logging events") + + return nil +} + +func Enable() error { + enableLock.Lock() + defer enableLock.Unlock() + + if enabled { + return errors.Errorf("Logger already enabled") + } + + levels, err := ParseLogLevelsFromArgs(cli.levels) + if err != nil { + return errors.WithMessagef(err, "Unable to parse levels") + } + + // Set root logger to stdout (JSON formatted) if not prettified + if strings.ToUpper(cli.format) == "JSON" { + Global().SetRoot(zerolog.New(os.Stdout).With().Timestamp().Logger()) + } else if strings.ToLower(cli.format) != "pretty" && cli.format != "" { + return errors.Errorf("Unknown log format: %s", cli.format) + } + Global().Configure(Config{ + Levels: levels, + Sampling: cli.sampling, + }) + + return nil +} diff --git a/pkg/util/errors/errors.go b/pkg/util/errors/errors.go index fd249da1c..221b8948a 100644 --- a/pkg/util/errors/errors.go +++ b/pkg/util/errors/errors.go @@ -31,8 +31,6 @@ import ( "github.com/pkg/errors" driver "github.com/arangodb/go-driver" - - "github.com/arangodb/kube-arangodb/pkg/logging" ) func Cause(err error) error { @@ -209,12 +207,6 @@ func libCause(err error) (bool, error) { } } -func LogError(logger logging.Logger, msg string, f func() error) { - if err := f(); err != nil { - logger.Err(err).Error(msg) - } -} - type Causer interface { Cause() error }