diff --git a/README.md b/README.md index e0f71db..cb99148 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # applog applog is a opinionated logger configuration. + +WARNING: do not use this library, the API is not stable and I make breaking changes at random. There's a reason it's not on GitHub yet, or possibly ever tbh. diff --git a/applog.go b/applog.go index ea96aef..007c439 100644 --- a/applog.go +++ b/applog.go @@ -22,21 +22,27 @@ var ( // AppLogOpts contains options for configuring the application logger. type AppLogOpts struct { - // Verbose enables verbose logging, which will use the LogOutput writer - // for pretty-printed console output. If false, console output is disabled. - Verbose bool + // ConsoleOutput is the writer for pretty-printed console logs. If nil, + // console output is disabled. Generally recommended to set this to + // os.Stderr, leaving os.Stdout for application output (usually via + // fmt.Print*). + ConsoleOutput io.Writer - // LogOutput is the output writer for the pretty-printed slog console - // logger that is enabled if Verbose is set to true. If nil, console - // output will be disabled. - LogOutput io.Writer + // ConsoleLevel is the minimum log level for console output. Defaults to + // slog.LevelInfo. + ConsoleLevel slog.Level - // LogFile is the file where JSON formatted logs will be written. If - // empty, log file output will be disabled. - LogFile string + // FileOutput is the path to a file where JSON formatted logs will be + // written. If empty, file output will be disabled. + FileOutput string + + // FileLevel is the minimum log level for file output. Defaults to + // slog.LevelInfo. + FileLevel slog.Level // SetDefault indicates whether to set the logger as the default logger - // for slog. Generally not recommended. + // for slog. Generally recommended to manage logger via app lifecycle + // instead of relying on globals. SetDefault bool } @@ -44,23 +50,14 @@ type AppLogOpts struct { func (opts AppLogOpts) Module() *app.Module { return app.NewModule(ModuleName, app.ModuleOpts{ Setup: func(m *app.Module) error { - if opts.LogFile == "" && (opts.LogOutput == nil || !opts.Verbose) { + if opts.FileOutput == "" && opts.ConsoleOutput == nil { return fmt.Errorf("no logging output configured") } - output := opts.LogOutput - if !opts.Verbose { - output = nil - } - - if err := setupLogger(m.Lifecycle(), opts.LogFile, output); err != nil { + if err := setupLogger(m.Lifecycle(), opts); err != nil { return fmt.Errorf("failed to set up logger: %w", err) } - if opts.SetDefault { - slog.SetDefault(m.Logger()) - } - return nil }, Teardown: func(m *app.Module) error { @@ -80,32 +77,37 @@ func Module(opts AppLogOpts) *app.Module { // and a tint handler for pretty-printed console output. May return an error // if the log file cannot be opened. Log file should be created if it does not // exist and appended to if it does. -func setupLogger(lifecycle *app.Lifecycle, logFilePath string, logoutput io.Writer) error { +func setupLogger(lifecycle *app.Lifecycle, opts AppLogOpts) error { handlers := make([]slog.Handler, 0) // If log file is specified, set up JSON file logging - if logFilePath != "" { + if opts.FileOutput != "" { var err error - logfile, err = os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + logfile, err = os.OpenFile(opts.FileOutput, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return err } - handlers = append(handlers, slog.NewJSONHandler(logfile, &slog.HandlerOptions{})) + handlers = append(handlers, slog.NewJSONHandler(logfile, &slog.HandlerOptions{ + Level: opts.FileLevel, + })) } // If log output is specified, set up pretty-printed console logging - if logoutput != nil { - handlers = append(handlers, tint.NewHandler(logoutput, &tint.Options{ - Level: slog.LevelDebug, + if opts.ConsoleOutput != nil { + handlers = append(handlers, tint.NewHandler(opts.ConsoleOutput, &tint.Options{ + Level: opts.ConsoleLevel, TimeFormat: time.Kitchen, })) } - logger := slog.New( - slogmulti.Fanout(handlers...), - ) - lifecycle.WithLogger(logger) + logger := slog.New(slogmulti.Fanout(handlers...)) + lifecycle.WithLogger(logger) // set logger on lifecycle + + // optionally set logger as slog default (not recommended) + if opts.SetDefault { + slog.SetDefault(logger) + } return nil }