From 26f279d130dd485784b466db555d8cb178a67e7f Mon Sep 17 00:00:00 2001 From: Jordan Rash <15827604+jordan-rash@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:38:14 +0200 Subject: [PATCH] elite logging (#178) --- go.mod | 5 ++-- go.sum | 10 ++++++++ internal/models/cli.go | 4 +++ nex/nex.go | 57 +++++++++++++++++++++--------------------- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 03c0427d..d6fab936 100644 --- a/go.mod +++ b/go.mod @@ -88,13 +88,14 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/jordan-rash/slog-handler v0.0.0-20240416152541-5a6f90904449 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // 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.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/minio/highwayhash v1.0.2 // indirect @@ -134,7 +135,7 @@ require ( golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.20.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.4.0 // indirect golang.org/x/tools v0.16.1 // indirect diff --git a/go.sum b/go.sum index a5f6bf86..2fddc58a 100644 --- a/go.sum +++ b/go.sum @@ -257,6 +257,12 @@ github.com/jedib0t/go-pretty/v6 v6.4.9/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVf github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jordan-rash/firecracker-go-sdk v0.0.0-20240124162534-a5295226c294 h1:gu6Xab0e7EXz3yYRNM8FsU0QmYeWkxjotPcHT+c+t3w= github.com/jordan-rash/firecracker-go-sdk v0.0.0-20240124162534-a5295226c294/go.mod h1:pcsIXRGgbFGr9QtUdlQCP/z6tuB7EMw6zXgFkcu7Q0c= +github.com/jordan-rash/slog-handler v0.0.0-20240329211950-0b604598c8db h1:PjeQk8zGRwWFOIqIK0kKABjdsre1xs/pMtP1hsfG7WM= +github.com/jordan-rash/slog-handler v0.0.0-20240329211950-0b604598c8db/go.mod h1:qAvCEsGWcbpvC1TrobMyjw7CKr5P5flNnA3wnZ20yuw= +github.com/jordan-rash/slog-handler v0.0.0-20240416151542-3c7bb1abb435 h1:54U713/CzIBH1lwDY079nfR2lhWwXJLASxoTZb7u03I= +github.com/jordan-rash/slog-handler v0.0.0-20240416151542-3c7bb1abb435/go.mod h1:teeFXg8aOsombwXerVrB8Id0bkaPpZ+QuK6V6NYZW0c= +github.com/jordan-rash/slog-handler v0.0.0-20240416152541-5a6f90904449 h1:vve37iyU8masdeQVKKcQZLcclL9BHDiLOtf3W26h/LM= +github.com/jordan-rash/slog-handler v0.0.0-20240416152541-5a6f90904449/go.mod h1:teeFXg8aOsombwXerVrB8Id0bkaPpZ+QuK6V6NYZW0c= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -299,6 +305,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= @@ -618,6 +626,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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= diff --git a/internal/models/cli.go b/internal/models/cli.go index 3e2c2413..1037c382 100644 --- a/internal/models/cli.go +++ b/internal/models/cli.go @@ -53,6 +53,10 @@ type Options struct { // LogLevel is the log level to use LogLevel string // LogJSON enables JSON logging + LogTimeFormat string + // Timeformat for logs. Must satisfy time.Time format criteria + LogsColorized bool + // Outputs logs with color LogJSON bool // Name or path to a configuration context ConfigurationContext string diff --git a/nex/nex.go b/nex/nex.go index 8889629e..e1bbc9bf 100644 --- a/nex/nex.go +++ b/nex/nex.go @@ -6,9 +6,11 @@ import ( "log/slog" "os" "strconv" + "time" "github.com/choria-io/fisk" "github.com/fatih/color" + shandler "github.com/jordan-rash/slog-handler" "github.com/synadia-io/nex/internal/models" nextui "github.com/synadia-io/nex/nex/tui" ) @@ -18,11 +20,6 @@ var ( COMMIT = "" BUILDDATE = "" - LevelTrace = slog.Level(-8) - LevelNames = map[slog.Leveler]string{ - LevelTrace: "TRACE", - } - blue = color.New(color.FgBlue).SprintFunc() ncli = fisk.New("nex", fmt.Sprintf("%s\nNATS Execution Engine CLI Version %s\n", blue(Banner), VERSION)) @@ -74,8 +71,10 @@ func init() { ncli.Flag("tlsfirst", "Perform TLS handshake before expecting the server greeting").BoolVar(&Opts.TlsFirst) ncli.Flag("timeout", "Time to wait on responses from NATS").Default("2s").Envar("NATS_TIMEOUT").PlaceHolder("DURATION").DurationVar(&Opts.Timeout) ncli.Flag("namespace", "Scoping namespace for applicable operations").Default("default").Envar("NEX_NAMESPACE").StringVar(&Opts.Namespace) - ncli.Flag("loglevel", "Log level").Default("info").Envar("NEX_LOGLEVEL").EnumVar(&Opts.LogLevel, "trace", "debug", "info", "warn", "error") + ncli.Flag("loglevel", "Log level").Default("info").Envar("NEX_LOGLEVEL").EnumVar(&Opts.LogLevel, "debug", "info", "warn", "error") ncli.Flag("logjson", "Log JSON").Default("false").Envar("NEX_LOGJSON").UnNegatableBoolVar(&Opts.LogJSON) + ncli.Flag("logcolor", "Prints text logs with color").Envar("NEX_LOG_COLORIZED").Default("false").UnNegatableBoolVar(&Opts.LogsColorized) + ncli.Flag("timeformat", "How time is formatted in logger").Envar("NEX_LOG_TIMEFORMAT").Default("DateTime").EnumVar(&Opts.LogTimeFormat, "DateOnly", "DateTime", "Stamp", "RFC822", "RFC3339") ncli.Flag("context", "Configuration context").Envar("NATS_CONTEXT").PlaceHolder("NAME").StringVar(&Opts.ConfigurationContext) ncli.Flag("no-context", "Disable NATS context discovery").UnNegatableBoolVar(&Opts.SkipContexts) ncli.Flag("conn-name", "Name of NATS connection").Default(func() string { @@ -125,39 +124,41 @@ func main() { cmd := fisk.MustParse(ncli.Parse(os.Args[1:])) ctx := context.Background() - opts := slog.HandlerOptions{ - ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { - if a.Key == slog.LevelKey { - level := a.Value.Any().(slog.Level) - levelLabel, exists := LevelNames[level] - if !exists { - levelLabel = level.String() - } - a.Value = slog.StringValue(levelLabel) - } - return a - }, - } + var handlerOpts []shandler.HandlerOption switch Opts.LogLevel { case "debug": - opts.Level = slog.LevelDebug + handlerOpts = append(handlerOpts, shandler.WithLogLevel(slog.LevelDebug)) case "info": - opts.Level = slog.LevelInfo + handlerOpts = append(handlerOpts, shandler.WithLogLevel(slog.LevelInfo)) case "warn": - opts.Level = slog.LevelWarn - case "trace": - opts.Level = LevelTrace + handlerOpts = append(handlerOpts, shandler.WithLogLevel(slog.LevelWarn)) + default: + handlerOpts = append(handlerOpts, shandler.WithLogLevel(slog.LevelError)) + } + + switch Opts.LogTimeFormat { + case "DateOnly": + handlerOpts = append(handlerOpts, shandler.WithTimeFormat(time.DateOnly)) + case "Stamp": + handlerOpts = append(handlerOpts, shandler.WithTimeFormat(time.Stamp)) + case "RFC822": + handlerOpts = append(handlerOpts, shandler.WithTimeFormat(time.RFC822)) + case "RFC3339": + handlerOpts = append(handlerOpts, shandler.WithTimeFormat(time.RFC3339)) default: - opts.Level = slog.LevelError + handlerOpts = append(handlerOpts, shandler.WithTimeFormat(time.DateTime)) } var logger *slog.Logger if Opts.LogJSON { - logger = slog.New(slog.NewJSONHandler(os.Stdout, &opts)) - } else { - logger = slog.New(slog.NewTextHandler(os.Stdout, &opts)) + handlerOpts = append(handlerOpts, shandler.WithJSON()) } + if Opts.LogsColorized { + handlerOpts = append(handlerOpts, shandler.WithColor()) + } + + logger = slog.New(shandler.NewHandler(handlerOpts...)) switch cmd { case tui.FullCommand():