diff --git a/internal/chart/v3/util/dependencies.go b/internal/chart/v3/util/dependencies.go index 55a618f7f..d42069894 100644 --- a/internal/chart/v3/util/dependencies.go +++ b/internal/chart/v3/util/dependencies.go @@ -30,7 +30,7 @@ import ( // ProcessDependencies checks through this chart's dependencies, processing accordingly. func ProcessDependencies(c *chart.Chart, v common.Values) error { - logger := slog.Default() + logger := slog.New(slog.DiscardHandler) if err := processDependencyEnabled(c, v, "", logger); err != nil { return err } diff --git a/internal/plugin/loader.go b/internal/plugin/loader.go index d99395641..02c48ee71 100644 --- a/internal/plugin/loader.go +++ b/internal/plugin/loader.go @@ -159,9 +159,19 @@ func LoadDir(dirname string) (Plugin, error) { return pm.CreatePlugin(dirname, m) } +// NewLogIgnorePluginLoadErrorFilterFunc returns an ErrorFilterFunc that logs +// plugin load errors using the provided logger and ignores them. +func NewLogIgnorePluginLoadErrorFilterFunc(logger *slog.Logger) ErrorFilterFunc { + return func(pluginYAML string, err error) error { + logger.Warn("failed to load plugin (ignoring)", slog.String("plugin_yaml", pluginYAML), slog.Any("error", err)) + return nil + } +} + +// LogIgnorePluginLoadErrorFilterFunc logs plugin load errors and ignores them. +// Deprecated: Use NewLogIgnorePluginLoadErrorFilterFunc to inject a logger. func LogIgnorePluginLoadErrorFilterFunc(pluginYAML string, err error) error { - slog.Warn("failed to load plugin (ignoring)", slog.String("plugin_yaml", pluginYAML), slog.Any("error", err)) - return nil + return NewLogIgnorePluginLoadErrorFilterFunc(slog.New(slog.DiscardHandler))(pluginYAML, err) } // errorFilterFunc is a function that can filter errors during plugin loading @@ -205,13 +215,20 @@ type findFunc func(pluginsDir string) ([]Plugin, error) // filterFunc is a function that filters plugins type filterFunc func(Plugin) bool -// FindPlugins returns a list of plugins that match the descriptor -// Errors loading a plugin are ignored with a warning -func FindPlugins(pluginsDirs []string, descriptor Descriptor) ([]Plugin, error) { - loadAllIgnoreErrors := func(pluginsDir string) ([]Plugin, error) { - return LoadAllDir(pluginsDir, LogIgnorePluginLoadErrorFilterFunc) +// FindPluginsWithErrorFilter returns a list of plugins that match the descriptor, +// using the provided error filter to handle individual plugin load errors. +func FindPluginsWithErrorFilter(pluginsDirs []string, descriptor Descriptor, errFilter ErrorFilterFunc) ([]Plugin, error) { + loadAll := func(pluginsDir string) ([]Plugin, error) { + return LoadAllDir(pluginsDir, errFilter) } - return findPlugins(pluginsDirs, loadAllIgnoreErrors, makeDescriptorFilter(descriptor)) + return findPlugins(pluginsDirs, loadAll, makeDescriptorFilter(descriptor)) +} + +// FindPlugins returns a list of plugins that match the descriptor. +// Errors loading a plugin are silently ignored. +// Deprecated: Use FindPluginsWithErrorFilter to handle load errors explicitly. +func FindPlugins(pluginsDirs []string, descriptor Descriptor) ([]Plugin, error) { + return FindPluginsWithErrorFilter(pluginsDirs, descriptor, LogIgnorePluginLoadErrorFilterFunc) } // findPlugins is the internal implementation that uses the find and filter functions diff --git a/pkg/chart/common/util/jsonschema.go b/pkg/chart/common/util/jsonschema.go index 9fd1ad85b..ef9a2b0c9 100644 --- a/pkg/chart/common/util/jsonschema.go +++ b/pkg/chart/common/util/jsonschema.go @@ -74,7 +74,7 @@ func newHTTPURLLoader() *HTTPURLLoader { // ValidateAgainstSchema checks that values does not violate the structure laid out in schema func ValidateAgainstSchema(ch chart.Charter, values map[string]any) error { - logger := slog.Default() + logger := slog.New(slog.DiscardHandler) chrt, err := chart.NewAccessor(ch) if err != nil { return err @@ -123,7 +123,7 @@ func ValidateAgainstSchema(ch chart.Charter, values map[string]any) error { // ValidateAgainstSingleSchema checks that values does not violate the structure laid out in this schema func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte) (reterr error) { - logger := slog.Default() + logger := slog.New(slog.DiscardHandler) defer func() { if r := recover(); r != nil { reterr = fmt.Errorf("unable to validate schema: %s", r) diff --git a/pkg/chart/v2/util/dependencies.go b/pkg/chart/v2/util/dependencies.go index f2740726d..6d27b2c6d 100644 --- a/pkg/chart/v2/util/dependencies.go +++ b/pkg/chart/v2/util/dependencies.go @@ -30,7 +30,7 @@ import ( // ProcessDependencies checks through this chart's dependencies, processing accordingly. func ProcessDependencies(c *chart.Chart, v common.Values) error { - logger := slog.Default() + logger := slog.New(slog.DiscardHandler) if err := processDependencyEnabled(c, v, "", logger); err != nil { return err } diff --git a/pkg/cmd/load_plugins.go b/pkg/cmd/load_plugins.go index 065f819c0..9f6818c13 100644 --- a/pkg/cmd/load_plugins.go +++ b/pkg/cmd/load_plugins.go @@ -62,7 +62,7 @@ func loadCLIPlugins(baseCmd *cobra.Command, out io.Writer, logger *slog.Logger) descriptor := plugin.Descriptor{ Type: "cli/v1", } - found, err := plugin.FindPlugins(dirs, descriptor) + found, err := plugin.FindPluginsWithErrorFilter(dirs, descriptor, plugin.NewLogIgnorePluginLoadErrorFilterFunc(logger)) if err != nil { logger.Error("failed to load plugins", slog.String("error", err.Error())) return diff --git a/pkg/cmd/plugin_list.go b/pkg/cmd/plugin_list.go index 726d63b79..8917e6359 100644 --- a/pkg/cmd/plugin_list.go +++ b/pkg/cmd/plugin_list.go @@ -42,7 +42,7 @@ func newPluginListCmd(out io.Writer, logger *slog.Logger) *cobra.Command { descriptor := plugin.Descriptor{ Type: pluginType, } - plugins, err := plugin.FindPlugins(dirs, descriptor) + plugins, err := plugin.FindPluginsWithErrorFilter(dirs, descriptor, plugin.NewLogIgnorePluginLoadErrorFilterFunc(logger)) if err != nil { return err } diff --git a/pkg/cmd/plugin_uninstall.go b/pkg/cmd/plugin_uninstall.go index db18bf74f..c69eba8b2 100644 --- a/pkg/cmd/plugin_uninstall.go +++ b/pkg/cmd/plugin_uninstall.go @@ -63,7 +63,7 @@ func (o *pluginUninstallOptions) complete(args []string) error { func (o *pluginUninstallOptions) run(out io.Writer) error { o.logger.Debug("loading installer plugins", "dir", settings.PluginsDirectory) - plugins, err := plugin.LoadAllDir(settings.PluginsDirectory, plugin.LogIgnorePluginLoadErrorFilterFunc) + plugins, err := plugin.LoadAllDir(settings.PluginsDirectory, plugin.NewLogIgnorePluginLoadErrorFilterFunc(o.logger)) if err != nil { return err } diff --git a/pkg/cmd/plugin_update.go b/pkg/cmd/plugin_update.go index ffd701224..523427059 100644 --- a/pkg/cmd/plugin_update.go +++ b/pkg/cmd/plugin_update.go @@ -63,7 +63,7 @@ func (o *pluginUpdateOptions) complete(args []string) error { func (o *pluginUpdateOptions) run(out io.Writer) error { o.logger.Debug("loading installed plugins", "path", settings.PluginsDirectory) - plugins, err := plugin.LoadAllDir(settings.PluginsDirectory, plugin.LogIgnorePluginLoadErrorFilterFunc) + plugins, err := plugin.LoadAllDir(settings.PluginsDirectory, plugin.NewLogIgnorePluginLoadErrorFilterFunc(o.logger)) if err != nil { return err } diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 75697126c..808065fff 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -177,7 +177,6 @@ func newRootCmdWithConfig(actionConfig *action.Configuration, out io.Writer, arg flags.Parse(args) logger := logSetup(settings.Debug) - slog.SetDefault(logger) actionConfig.SetLogger(logger.Handler()) // Validate color mode setting diff --git a/pkg/cmd/root_test.go b/pkg/cmd/root_test.go index 4e53e1c82..78fe0fa6c 100644 --- a/pkg/cmd/root_test.go +++ b/pkg/cmd/root_test.go @@ -149,9 +149,9 @@ func TestRootCmdLogger(t *testing.T) { t.Error("expected actionConfig logger to be set, got discard handler") } - // slog.SetDefault is called so the global default should use the same handler - if l.Handler() != slog.Default().Handler() { - t.Error("expected actionConfig logger to match the global slog default logger") + // slog.SetDefault is not called, so the global default should differ from the actionConfig logger + if l.Handler() == slog.Default().Handler() { + t.Error("expected actionConfig logger to differ from the global slog default logger") } } diff --git a/pkg/getter/getter.go b/pkg/getter/getter.go index a2d0f0ee2..0a5ebbf50 100644 --- a/pkg/getter/getter.go +++ b/pkg/getter/getter.go @@ -19,6 +19,7 @@ package getter import ( "bytes" "fmt" + "log/slog" "net/http" "slices" "time" @@ -49,6 +50,7 @@ type getterOptions struct { timeout time.Duration transport *http.Transport artifactType string + logger *slog.Logger } // Option allows specifying various settings configurable by the user for overriding the defaults @@ -152,6 +154,13 @@ func WithArtifactType(artifactType string) Option { } } +// WithLogger sets the logger for the getter. +func WithLogger(logger *slog.Logger) Option { + return func(opts *getterOptions) { + opts.logger = logger + } +} + // Getter is an interface to support GET to the specified URL. type Getter interface { // Get file content by url string diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index 2eb2d5d8c..639fb6494 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -88,13 +88,17 @@ func (g *HTTPGetter) get(href string, opts getterOptions) (*bytes.Buffer, error) return nil, err } - slog.Debug("fetching", "url", href) + logger := opts.logger + if logger == nil { + logger = slog.New(slog.DiscardHandler) + } + logger.Debug("fetching", "url", href) resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() - slog.Debug("fetch complete", "url", href, "status", resp.Status, "content-length", resp.ContentLength) + logger.Debug("fetch complete", "url", href, "status", resp.Status, "content-length", resp.ContentLength) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("failed to fetch %s : %s", href, resp.Status) } diff --git a/pkg/repo/v1/index.go b/pkg/repo/v1/index.go index d3250281c..58f7242ec 100644 --- a/pkg/repo/v1/index.go +++ b/pkg/repo/v1/index.go @@ -99,7 +99,7 @@ func (i IndexFile) log() *slog.Logger { if i.Logger != nil { return i.Logger } - return slog.Default() + return slog.New(slog.DiscardHandler) } // NewIndexFile initializes an index.