diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db9944bb..6efdb8f4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: run-on: [ 'ubuntu', 'macOS', 'windows' ] - go-version: [ 'oldstable', 'stable' ] + go-version: [ 'stable' ] name: Test runs-on: ${{ matrix.run-on }}-latest steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 6feb987b..1f78e177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Removed + +- Remove konf.Logger in favor of slog (#48). + ## [v0.2.0] - 3/18/2023 ### Removed diff --git a/config.go b/config.go index f2a4afa9..cbe6aeba 100644 --- a/config.go +++ b/config.go @@ -7,6 +7,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strings" "sync" @@ -18,7 +19,6 @@ import ( // Config is a registry which holds configuration loaded by Loader(s). type Config struct { delimiter string - logger Logger values map[string]any providers []*provider @@ -45,7 +45,7 @@ func New(opts ...Option) (*Config, error) { return nil, fmt.Errorf("[konf] load configuration: %w", err) } maps.Merge(config.values, values) - config.logger.Info( + slog.Info( "Configuration has been loaded.", "loader", loader, ) @@ -170,7 +170,7 @@ func (c *Config) Watch(ctx context.Context, fns ...func(*Config)) error { //noli ctx, func(values map[string]any) { provider.values = values - c.logger.Info( + slog.Info( "Configuration has been changed.", "watcher", provider.watcher, ) diff --git a/config_test.go b/config_test.go index cf1905b3..fb24c5e2 100644 --- a/config_test.go +++ b/config_test.go @@ -254,25 +254,3 @@ type errorLoader struct{} func (errorLoader) Load() (map[string]any, error) { return nil, errors.New("load error") } - -func TestConfig_logger(t *testing.T) { - t.Parallel() - - logger := &logger{} - _, err := konf.New(konf.WithLogger(logger), konf.WithLoader(mapLoader{})) - require.NoError(t, err) - - require.Equal(t, "Configuration has been loaded.", logger.message) - require.Equal(t, []any{"loader", mapLoader{"configured": true}}, logger.keyAndValues) -} - -type logger struct { - konf.Logger - message string - keyAndValues []any -} - -func (l *logger) Info(message string, keyAndValues ...any) { - l.message = message - l.keyAndValues = keyAndValues -} diff --git a/global.go b/global.go index c7c3b0aa..e254c12a 100644 --- a/global.go +++ b/global.go @@ -5,6 +5,7 @@ package konf import ( "context" + "log/slog" "reflect" "sync" @@ -21,9 +22,9 @@ func Get[T any](path string) T { //nolint:ireturn var value T if err := global.Unmarshal(path, &value); err != nil { - global.logger.Error( + slog.Error( "Could not read config, return empty value instead.", - err, + "error", err, "path", path, "type", reflect.TypeOf(value), ) diff --git a/global_test.go b/global_test.go index a8ed1fa9..dbf49981 100644 --- a/global_test.go +++ b/global_test.go @@ -47,8 +47,8 @@ func TestGet_error(t *testing.T) { log.SetFlags(0) require.False(t, konf.Get[bool]("config")) - expected := "Error Could not read config, return empty value instead." + - " error=[konf] decode: cannot parse '' as bool: strconv.ParseBool: parsing \"string\": invalid syntax" + + expected := "ERROR Could not read config, return empty value instead." + + " error=\"[konf] decode: cannot parse '' as bool: strconv.ParseBool: parsing \\\"string\\\": invalid syntax\"" + " path=config type=bool\n" require.Equal(t, expected, buf.String()) } diff --git a/go.mod b/go.mod index b315a597..dd34f9c1 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ktong/konf -go 1.20 +go 1.21 require ( github.com/fsnotify/fsnotify v1.7.0 diff --git a/logger.go b/logger.go deleted file mode 100644 index b92c8b26..00000000 --- a/logger.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2023 The konf authors -// Use of this source code is governed by a MIT license found in the LICENSE file. - -package konf - -import ( - "bytes" - "fmt" - "log" -) - -// Logger is the interface that wraps the basic methods for logging. -type Logger interface { - Info(message string, keyAndValues ...any) - Error(message string, err error, keyAndValues ...any) -} - -type stdlog struct{} - -func (l stdlog) Info(message string, keyAndValues ...any) { - l.log("Info", message, keyAndValues...) -} - -func (l stdlog) Error(message string, err error, keyAndValues ...any) { - if err != nil { - keyAndValues = append([]any{"error", err.Error()}, keyAndValues...) - } - - l.log("Error", message, keyAndValues...) -} - -func (stdlog) log(level, message string, keyAndValues ...any) { - buf := new(bytes.Buffer) - buf.WriteString(level) - buf.WriteRune(' ') - buf.WriteString(message) - for i := 0; i < len(keyAndValues); i += 2 { - buf.WriteRune(' ') - buf.WriteString(fmt.Sprintf("%s=%v", keyAndValues[i], keyAndValues[i+1])) - } - - log.Print(buf) -} diff --git a/option.go b/option.go index 156efac4..f0dc673c 100644 --- a/option.go +++ b/option.go @@ -22,15 +22,6 @@ func WithDelimiter(delimiter string) Option { } } -// WithLogger provides a Logger implementation to logger. -// -// The default implementation is using standard [log]. -func WithLogger(logger Logger) Option { - return func(config *options) { - config.logger = logger - } -} - // Option configures the given Config. type Option func(*options) @@ -44,7 +35,6 @@ func apply(opts []Option) options { option := &options{ Config: &Config{ delimiter: ".", - logger: stdlog{}, values: make(map[string]any), }, } diff --git a/provider/file/file.go b/provider/file/file.go index a305872e..f3616983 100644 --- a/provider/file/file.go +++ b/provider/file/file.go @@ -17,7 +17,7 @@ package file import ( "fmt" "io/fs" - "log" + "log/slog" "os" ) @@ -47,7 +47,7 @@ func (f File) Load() (map[string]any, error) { } if err != nil { if f.ignoreNotExist && os.IsNotExist(err) { - log.Printf("Config file %s does not exist.", f.path) + slog.Warn("Config file does not exist.", "file", f.path) return make(map[string]any), nil } diff --git a/provider/file/file_test.go b/provider/file/file_test.go index 723c34bd..5731e198 100644 --- a/provider/file/file_test.go +++ b/provider/file/file_test.go @@ -6,11 +6,9 @@ package file_test import ( - "bytes" "context" "errors" "io/fs" - "log" "os" "path/filepath" "strings" @@ -122,20 +120,6 @@ func TestFile_Load(t *testing.T) { } } -func TestFile_log(t *testing.T) { - buf := new(bytes.Buffer) - log.SetOutput(buf) - log.SetFlags(0) - - _, err := file.New( - "not_found.json", - file.IgnoreFileNotExit(), - ).Load() - - require.NoError(t, err) - require.Equal(t, "Config file not_found.json does not exist.\n", buf.String()) -} - func TestFile_Watch(t *testing.T) { testcases := []struct { description string diff --git a/provider/file/watch.go b/provider/file/watch.go index 82abf5ac..45168c8f 100644 --- a/provider/file/watch.go +++ b/provider/file/watch.go @@ -8,7 +8,7 @@ package file import ( "context" "fmt" - "log" + "log/slog" "path/filepath" "time" @@ -26,7 +26,7 @@ func (f File) Watch(ctx context.Context, watchFunc func(map[string]any)) error { } defer func() { if err := watcher.Close(); err != nil { - log.Printf("Error when closing watcher for %s: %v", f.path, err) + slog.Error("Error when closing file watcher.", "file", f.path, "error", err) } }() @@ -73,12 +73,12 @@ func (f File) Watch(ctx context.Context, watchFunc func(map[string]any)) error { switch { case event.Has(fsnotify.Remove): - log.Printf("Config file %s has been removed.", f.path) + slog.Warn("Config file has been removed.", "file", f.path) watchFunc(nil) case event.Has(fsnotify.Create) || event.Has(fsnotify.Write): values, err := f.Load() if err != nil { - log.Printf("Error when reloading configuration from %s: %v", f.path, err) + slog.Error("Error when reloading config file", "file", f.path, "error", err) continue } @@ -90,7 +90,7 @@ func (f File) Watch(ctx context.Context, watchFunc func(map[string]any)) error { return nil } - log.Printf("Error when watching file %s: %v", f.path, err) + slog.Error("Error when watching file", "file", f.path, "error", err) case <-ctx.Done(): return nil diff --git a/provider/file/watch_unsupported.go b/provider/file/watch_unsupported.go index 618cb06b..c72ef6b0 100644 --- a/provider/file/watch_unsupported.go +++ b/provider/file/watch_unsupported.go @@ -7,12 +7,12 @@ package file import ( "context" - "log" + "log/slog" "runtime" ) func (f File) Watch(context.Context, func(map[string]any)) error { - log.Printf("File.Watch does not supported on %s.", runtime.GOOS) + slog.Warn("File.Watch does not supported on runtime.", "runtime", runtime.GOOS) return nil }