From a913318ae35fc6f536e8d062acdd4a60bd8c76be Mon Sep 17 00:00:00 2001 From: Maxime Leroy <19607336+maxime1907@users.noreply.github.com> Date: Wed, 5 Oct 2022 14:42:34 +0200 Subject: [PATCH] feat: support advanced zap configuration Signed-off-by: Maxime Leroy <19607336+maxime1907@users.noreply.github.com> --- Dockerfile | 1 + Makefile | 2 +- cmd/goldpinger/main.go | 57 +++++++++++++++++++++++++--------------- config/zap.json | 21 +++++++++++++++ pkg/goldpinger/config.go | 13 ++++----- 5 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 config/zap.json diff --git a/Dockerfile b/Dockerfile index ef709c3..1beb660 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,7 @@ RUN go mod vendor FROM scratch as simple COPY --from=builder /w/bin/goldpinger /goldpinger COPY ./static /static +COPY ./config /config ENTRYPOINT ["/goldpinger", "--static-file-path", "/static"] # For vendor builds, use the simple build and add the vendor'd files diff --git a/Makefile b/Makefile index 229e61a..d71055e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ name ?= goldpinger -version ?= v3.4.0 +version ?= v3.7.0 bin ?= goldpinger pkg ?= "github.com/bloomberg/goldpinger" tag = $(name):$(version) diff --git a/cmd/goldpinger/main.go b/cmd/goldpinger/main.go index 62303e7..3a2d002 100644 --- a/cmd/goldpinger/main.go +++ b/cmd/goldpinger/main.go @@ -15,8 +15,11 @@ package main import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" "os" - "strconv" "time" "github.com/go-openapi/loads" @@ -37,37 +40,32 @@ var ( Version, Build string ) -func getLogger() *zap.Logger { +func getLogger(zapconfigpath string) (*zap.Logger, error) { var logger *zap.Logger var err error - // We haven't parsed flags at this stage and that might be error prone - // so just use an envvar - if debug, err := strconv.ParseBool(os.Getenv("DEBUG")); err == nil && debug { - logger, err = zap.NewDevelopment() - } else { - logger, err = zap.NewProduction() + zapconfigJSON, err := ioutil.ReadFile(zapconfigpath) + if err != nil { + return nil, fmt.Errorf("Could not read zap config file: %w", err) + } + + var cfg zap.Config + if err := json.Unmarshal(zapconfigJSON, &cfg); err != nil { + return nil, fmt.Errorf("Could not read zap config as json: %w", err) } + logger, err = cfg.Build() if err != nil { - panic(err) + return nil, fmt.Errorf("Could not build zap config: %w", err) } - zap.ReplaceGlobals(logger) - return logger + + return logger, nil } func main() { - logger := getLogger() - defer logger.Sync() - - undo := zap.RedirectStdLog(logger) - defer undo() - - logger.Info("Goldpinger", zap.String("version", Version), zap.String("build", Build)) - // load embedded swagger file swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "") if err != nil { - logger.Error("Coud not parse swagger", zap.Error(err)) + log.Fatalf("Could not parse swagger: %v", err) } // create new service API @@ -84,7 +82,7 @@ func main() { for _, optsGroup := range api.CommandLineOptionsGroups { _, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options) if err != nil { - logger.Error("Coud not add flag group", zap.Error(err)) + log.Fatalf("Could not add flag group: %v", err) } } @@ -98,6 +96,23 @@ func main() { os.Exit(code) } + // Configure logger + logger, err := getLogger(goldpinger.GoldpingerConfig.ZapConfigPath) + if err != nil { + var errDev error + logger, errDev = zap.NewDevelopment() + if errDev != nil { + log.Fatalf("Could not build a development logger: %v", errDev) + } + logger.Warn("Logger could not be built, defaulting to development settings", zap.String("error", fmt.Sprintf("%v", err))) + } + defer logger.Sync() + + undo := zap.RedirectStdLog(logger) + defer undo() + + logger.Info("Goldpinger", zap.String("version", Version), zap.String("build", Build)) + if goldpinger.GoldpingerConfig.Namespace == nil { goldpinger.GoldpingerConfig.Namespace = &goldpinger.PodNamespace } else { diff --git a/config/zap.json b/config/zap.json new file mode 100644 index 0000000..19a4dfc --- /dev/null +++ b/config/zap.json @@ -0,0 +1,21 @@ +{ + "level": "info", + "encoding": "json", + "outputPaths": [ + "stdout" + ], + "errorOutputPaths": [ + "stderr" + ], + "initialFields": { + }, + "encoderConfig": { + "messageKey": "message", + "levelKey": "level", + "levelEncoder": "lowercase", + "timeKey": "ts", + "timeEncoder": "ISO8601", + "callerKey": "caller", + "callerEncoder": "Short" + } +} diff --git a/pkg/goldpinger/config.go b/pkg/goldpinger/config.go index 3b8abd7..0a6aa09 100644 --- a/pkg/goldpinger/config.go +++ b/pkg/goldpinger/config.go @@ -23,6 +23,7 @@ import ( // GoldpingerConfig represents the configuration for goldpinger var GoldpingerConfig = struct { StaticFilePath string `long:"static-file-path" description:"Folder for serving static files" env:"STATIC_FILE_PATH"` + ZapConfigPath string `long:"zap-config" description:"Path to zap config file" env:"ZAP_CONFIG" default:"/config/zap.json"` KubeConfigPath string `long:"kubeconfig" description:"Path to kubeconfig file" env:"KUBECONFIG"` RefreshInterval int `long:"refresh-interval" description:"If > 0, will create a thread and collect stats every n seconds" env:"REFRESH_INTERVAL" default:"30"` JitterFactor float64 `long:"jitter-factor" description:"The amount of jitter to add while pinging clients" env:"JITTER_FACTOR" default:"0.05"` @@ -47,10 +48,10 @@ var GoldpingerConfig = struct { PingTimeoutMs int64 `long:"ping-timeout-ms" description:"The timeout in milliseconds for a ping call to other goldpinger pods(deprecated)" env:"PING_TIMEOUT_MS" default:"300"` CheckTimeoutMs int64 `long:"check-timeout-ms" description:"The timeout in milliseconds for a check call to other goldpinger pods(deprecated)" env:"CHECK_TIMEOUT_MS" default:"1000"` CheckAllTimeoutMs int64 `long:"check-all-timeout-ms" description:"The timeout in milliseconds for a check-all call to other goldpinger pods(deprecated)" env:"CHECK_ALL_TIMEOUT_MS" default:"5000"` - PingTimeout time.Duration `long:"ping-timeout" description:"The timeout for a ping call to other goldpinger pods" env:"PING_TIMEOUT" default:"300ms"` - CheckTimeout time.Duration `long:"check-timeout" description:"The timeout for a check call to other goldpinger pods" env:"CHECK_TIMEOUT" default:"1000ms"` - CheckAllTimeout time.Duration `long:"check-all-timeout" description:"The timeout for a check-all call to other goldpinger pods" env:"CHECK_ALL_TIMEOUT" default:"5000ms"` - TCPCheckTimeout time.Duration `long:"tcp-targets-timeout" description:"The timeout for a tcp check on the provided tcp-targets" env:"TCP_TARGETS_TIMEOUT" default:"500ms"` - DnsCheckTimeout time.Duration `long:"dns-targets-timeout" description:"The timeout for a dns check on the provided dns-targets" env:"DNS_TARGETS_TIMEOUT" default:"500ms"` - HTTPCheckTimeout time.Duration `long:"http-targets-timeout" description:"The timeout for a http check on the provided http-targets" env:"HTTP_TARGETS_TIMEOUT" default:"500ms"` + PingTimeout time.Duration `long:"ping-timeout" description:"The timeout for a ping call to other goldpinger pods" env:"PING_TIMEOUT" default:"300ms"` + CheckTimeout time.Duration `long:"check-timeout" description:"The timeout for a check call to other goldpinger pods" env:"CHECK_TIMEOUT" default:"1000ms"` + CheckAllTimeout time.Duration `long:"check-all-timeout" description:"The timeout for a check-all call to other goldpinger pods" env:"CHECK_ALL_TIMEOUT" default:"5000ms"` + TCPCheckTimeout time.Duration `long:"tcp-targets-timeout" description:"The timeout for a tcp check on the provided tcp-targets" env:"TCP_TARGETS_TIMEOUT" default:"500ms"` + DnsCheckTimeout time.Duration `long:"dns-targets-timeout" description:"The timeout for a dns check on the provided dns-targets" env:"DNS_TARGETS_TIMEOUT" default:"500ms"` + HTTPCheckTimeout time.Duration `long:"http-targets-timeout" description:"The timeout for a http check on the provided http-targets" env:"HTTP_TARGETS_TIMEOUT" default:"500ms"` }{}