From 780a8273c5ade0bbe8aa9f80af2a3bdc1e8b1a4b Mon Sep 17 00:00:00 2001 From: Jon Chappelow Date: Tue, 17 Dec 2024 18:27:15 -0600 Subject: [PATCH] configurable log outputs --- app/node/node.go | 41 +++++++++++++++++++++++++++++------------ app/root.go | 2 +- config/config.go | 3 ++- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/app/node/node.go b/app/node/node.go index 9ddcff5b1..eacb5e72e 100644 --- a/app/node/node.go +++ b/app/node/node.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" "runtime" + "slices" "github.com/kwilteam/kwil-db/app/key" "github.com/kwilteam/kwil-db/config" @@ -43,22 +44,38 @@ type server struct { } func runNode(ctx context.Context, rootDir string, cfg *config.Config) (err error) { - // Writing to stdout and a log file. TODO: config outputs - rot, err := log.NewRotatorWriter(filepath.Join(rootDir, "kwild.log"), 10_000, 0) - if err != nil { - return fmt.Errorf("failed to create log rotator: %w", err) + var logWriters []io.Writer + if idx := slices.Index(cfg.LogOutput, "stdout"); idx != -1 { + logWriters = append(logWriters, os.Stdout) + cfg.LogOutput = slices.Delete(cfg.LogOutput, idx, idx+1) } - defer func() { - if err := rot.Close(); err != nil { - fmt.Printf("failed to close log rotator: %v", err) + if idx := slices.Index(cfg.LogOutput, "stderr"); idx != -1 { + logWriters = append(logWriters, os.Stderr) + cfg.LogOutput = slices.Delete(cfg.LogOutput, idx, idx+1) + } + + for _, logFile := range cfg.LogOutput { + rootedLogFile := rootedPath(logFile, rootDir) + rot, err := log.NewRotatorWriter(rootedLogFile, 10_000, 0) + if err != nil { + return fmt.Errorf("failed to create log rotator: %w", err) } - }() + defer func() { + if err := rot.Close(); err != nil { + fmt.Printf("failed to close log rotator: %v", err) + } + }() + logWriters = append(logWriters, rot) + } - logWriter := io.MultiWriter(os.Stdout, rot) // tee to stdout and log file + logger := log.DiscardLogger + if len(logWriters) > 0 { + logWriter := io.MultiWriter(logWriters...) - logger := log.New(log.WithLevel(cfg.LogLevel), log.WithFormat(cfg.LogFormat), - log.WithName("KWILD"), log.WithWriter(logWriter)) - // NOTE: level and name can be set independently for different systems + logger = log.New(log.WithLevel(cfg.LogLevel), log.WithFormat(cfg.LogFormat), + log.WithName("KWILD"), log.WithWriter(logWriter)) + // NOTE: level and name can be set independently for different systems + } logger.Infof("Starting kwild version %v", version.KwilVersion) diff --git a/app/root.go b/app/root.go index ca7c082e3..97553afae 100644 --- a/app/root.go +++ b/app/root.go @@ -29,7 +29,7 @@ func RootCmd() *cobra.Command { cmd := &cobra.Command{ Use: custom.BinaryConfig.NodeCmd, Short: custom.BinaryConfig.ProjectName + " daemon", - Long: custom.BinaryConfig.ProjectName + " main application (node and utilities)", + Long: custom.BinaryConfig.ProjectName + " node and utilities", DisableAutoGenTag: true, SilenceUsage: true, CompletionOptions: cobra.CompletionOptions{ diff --git a/config/config.go b/config/config.go index b8c98111d..ed34ddc60 100644 --- a/config/config.go +++ b/config/config.go @@ -152,6 +152,7 @@ func DefaultConfig() *Config { return &Config{ LogLevel: log.LevelInfo, LogFormat: log.FormatUnstructured, + LogOutput: []string{"stdout", "kwild.log"}, P2P: PeerConfig{ IP: "0.0.0.0", Port: 6600, @@ -206,7 +207,7 @@ func DefaultConfig() *Config { type Config struct { LogLevel log.Level `toml:"log_level" comment:"log level\npossible values: 'debug', 'info', 'warn', and 'error'"` LogFormat log.Format `toml:"log_format" comment:"log format\npossible values: 'json', 'text' (kv), and 'plain' (fmt-style)"` - // LogOutput []string `toml:"log_output" comment:"output paths for the log"` + LogOutput []string `toml:"log_output" comment:"output paths for the log"` ProfileMode string `toml:"profile_mode,commented" comment:"profile mode (http, cpu, mem, mutex, or block)"` ProfileFile string `toml:"profile_file,commented" comment:"profile output file path (e.g. cpu.pprof)"`