diff --git a/common/loggers/logger.go b/common/loggers/logger.go index c4d81fb8305..f851513b3eb 100644 --- a/common/loggers/logger.go +++ b/common/loggers/logger.go @@ -179,9 +179,9 @@ type Logger interface { Debugln(v ...any) Error() logg.LevelLogger Errorf(format string, v ...any) + Erroridf(id, format string, v ...any) Errorln(v ...any) Errors() string - Errorsf(id, format string, v ...any) Info() logg.LevelLogger InfoCommand(command string) logg.LevelLogger Infof(format string, v ...any) @@ -197,6 +197,7 @@ type Logger interface { Warn() logg.LevelLogger WarnCommand(command string) logg.LevelLogger Warnf(format string, v ...any) + Warnidf(id, format string, v ...any) Warnln(v ...any) Deprecatef(fail bool, format string, v ...any) Trace(s logg.StringFunc) @@ -321,10 +322,20 @@ func (l *logAdapter) Errors() string { return l.errors.String() } -func (l *logAdapter) Errorsf(id, format string, v ...any) { +func (l *logAdapter) Erroridf(id, format string, v ...any) { + format += l.idfInfoStatement("error", id, format) l.errorl.WithField(FieldNameStatementID, id).Logf(format, v...) } +func (l *logAdapter) Warnidf(id, format string, v ...any) { + format += l.idfInfoStatement("warning", id, format) + l.warnl.WithField(FieldNameStatementID, id).Logf(format, v...) +} + +func (l *logAdapter) idfInfoStatement(what, id, format string) string { + return fmt.Sprintf("\nYou can suppress this %s by adding the following to your site configuration:\nignoreLogs = ['%s']", what, id) +} + func (l *logAdapter) Trace(s logg.StringFunc) { l.tracel.Log(s) } diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go index 5788e792bdb..26e40230537 100644 --- a/config/allconfig/allconfig.go +++ b/config/allconfig/allconfig.go @@ -206,7 +206,7 @@ func (c Config) cloneForLang() *Config { x.DisableKinds = copyStringSlice(x.DisableKinds) x.DisableLanguages = copyStringSlice(x.DisableLanguages) x.MainSections = copyStringSlice(x.MainSections) - x.IgnoreErrors = copyStringSlice(x.IgnoreErrors) + x.IgnoreLogs = copyStringSlice(x.IgnoreLogs) x.IgnoreFiles = copyStringSlice(x.IgnoreFiles) x.Theme = copyStringSlice(x.Theme) @@ -299,9 +299,9 @@ func (c *Config) CompileConfig(logger loggers.Logger) error { } } - ignoredErrors := make(map[string]bool) - for _, err := range c.IgnoreErrors { - ignoredErrors[strings.ToLower(err)] = true + ignoredLogIDs := make(map[string]bool) + for _, err := range c.IgnoreLogs { + ignoredLogIDs[strings.ToLower(err)] = true } baseURL, err := urls.NewBaseURLFromString(c.BaseURL) @@ -357,7 +357,7 @@ func (c *Config) CompileConfig(logger loggers.Logger) error { BaseURLLiveReload: baseURL, DisabledKinds: disabledKinds, DisabledLanguages: disabledLangs, - IgnoredErrors: ignoredErrors, + IgnoredLogs: ignoredLogIDs, KindOutputFormats: kindOutputFormats, CreateTitle: helpers.GetTitleFunc(c.TitleCaseStyle), IsUglyURLSection: isUglyURL, @@ -394,7 +394,7 @@ type ConfigCompiled struct { KindOutputFormats map[string]output.Formats DisabledKinds map[string]bool DisabledLanguages map[string]bool - IgnoredErrors map[string]bool + IgnoredLogs map[string]bool CreateTitle func(s string) string IsUglyURLSection func(section string) bool IgnoreFile func(filename string) bool @@ -501,8 +501,8 @@ type RootConfig struct { // Enable to disable the build lock file. NoBuildLock bool - // A list of error IDs to ignore. - IgnoreErrors []string + // A list of log IDs to ignore. + IgnoreLogs []string // A list of regexps that match paths to ignore. // Deprecated: Use the settings on module imports. diff --git a/config/allconfig/configlanguage.go b/config/allconfig/configlanguage.go index 71bd232de17..0b4c7427832 100644 --- a/config/allconfig/configlanguage.go +++ b/config/allconfig/configlanguage.go @@ -89,8 +89,8 @@ func (c ConfigLanguage) IsLangDisabled(lang string) bool { return c.config.C.DisabledLanguages[lang] } -func (c ConfigLanguage) IgnoredErrors() map[string]bool { - return c.config.C.IgnoredErrors +func (c ConfigLanguage) IgnoredLogs() map[string]bool { + return c.config.C.IgnoredLogs } func (c ConfigLanguage) NoBuildLock() bool { diff --git a/config/allconfig/load.go b/config/allconfig/load.go index eceed31f4ba..cb267422f15 100644 --- a/config/allconfig/load.go +++ b/config/allconfig/load.go @@ -141,6 +141,7 @@ func (l configLoader) applyConfigAliases() error { {Key: "indexes", Value: "taxonomies"}, {Key: "logI18nWarnings", Value: "printI18nWarnings"}, {Key: "logPathWarnings", Value: "printPathWarnings"}, + {Key: "ignoreErrors", Value: "ignoreLogs"}, } for _, alias := range aliases { diff --git a/config/configProvider.go b/config/configProvider.go index 2536639ead9..21d832f17e0 100644 --- a/config/configProvider.go +++ b/config/configProvider.go @@ -67,7 +67,7 @@ type AllProvider interface { NewContentEditor() string Timeout() time.Duration StaticDirs() []string - IgnoredErrors() map[string]bool + IgnoredLogs() map[string]bool WorkingDir() string EnableEmoji() bool } diff --git a/hugolib/integrationtest_builder.go b/hugolib/integrationtest_builder.go index a46ae72751c..222c8ec2dd7 100644 --- a/hugolib/integrationtest_builder.go +++ b/hugolib/integrationtest_builder.go @@ -57,6 +57,13 @@ func TestOptDebug() TestOpt { } } +// TestOptWarn will enable warn logging in integration tests. +func TestOptWarn() TestOpt { + return func(c *IntegrationTestConfig) { + c.LogLevel = logg.LevelWarn + } +} + // TestOptWithNFDOnDarwin will normalize the Unicode filenames to NFD on Darwin. func TestOptWithNFDOnDarwin() TestOpt { return func(c *IntegrationTestConfig) { @@ -181,9 +188,18 @@ func (b *lockingBuffer) Write(p []byte) (n int, err error) { return } -func (s *IntegrationTestBuilder) AssertLogContains(text string) { +func (s *IntegrationTestBuilder) AssertLogContains(els ...string) { s.Helper() - s.Assert(s.logBuff.String(), qt.Contains, text) + for _, el := range els { + s.Assert(s.logBuff.String(), qt.Contains, el) + } +} + +func (s *IntegrationTestBuilder) AssertLogNotContains(els ...string) { + s.Helper() + for _, el := range els { + s.Assert(s.logBuff.String(), qt.Not(qt.Contains), el) + } } func (s *IntegrationTestBuilder) AssertLogMatches(expression string) { diff --git a/hugolib/site_new.go b/hugolib/site_new.go index 0cab713520b..debb81e77b1 100644 --- a/hugolib/site_new.go +++ b/hugolib/site_new.go @@ -124,7 +124,7 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) { Stdout: cfg.LogOut, Stderr: cfg.LogOut, StoreErrors: conf.Running(), - SuppressStatements: conf.IgnoredErrors(), + SuppressStatements: conf.IgnoredLogs(), } logger = loggers.New(logOpts) } diff --git a/tpl/data/data.go b/tpl/data/data.go index 7eb730c4c06..78f1f3f48e2 100644 --- a/tpl/data/data.go +++ b/tpl/data/data.go @@ -94,7 +94,7 @@ func (ns *Namespace) GetCSV(sep string, args ...any) (d [][]string, err error) { if security.IsAccessDenied(err) { return nil, err } - ns.deps.Log.Errorsf(constants.ErrRemoteGetCSV, "Failed to get CSV resource %q: %s", url, err) + ns.deps.Log.Erroridf(constants.ErrRemoteGetCSV, "Failed to get CSV resource %q: %s", url, err) return nil, nil } @@ -132,7 +132,7 @@ func (ns *Namespace) GetJSON(args ...any) (any, error) { if security.IsAccessDenied(err) { return nil, err } - ns.deps.Log.Errorsf(constants.ErrRemoteGetJSON, "Failed to get JSON resource %q: %s", url, err) + ns.deps.Log.Erroridf(constants.ErrRemoteGetJSON, "Failed to get JSON resource %q: %s", url, err) return nil, nil } diff --git a/tpl/fmt/fmt.go b/tpl/fmt/fmt.go index 4f18758e043..04dbd339c56 100644 --- a/tpl/fmt/fmt.go +++ b/tpl/fmt/fmt.go @@ -68,9 +68,7 @@ func (ns *Namespace) Errorf(format string, args ...any) string { // an information text that the error with the given id can be suppressed in config. // It returns an empty string. func (ns *Namespace) Erroridf(id, format string, args ...any) string { - format += "\nYou can suppress this error by adding the following to your site configuration:\nignoreErrors = ['%s']" - args = append(args, id) - ns.logger.Errorsf(id, format, args...) + ns.logger.Erroridf(id, format, args...) return "" } @@ -81,6 +79,14 @@ func (ns *Namespace) Warnf(format string, args ...any) string { return "" } +// Warnidf formats args according to a format specifier and logs an WARNING and +// an information text that the warning with the given id can be suppressed in config. +// It returns an empty string. +func (ns *Namespace) Warnidf(id, format string, args ...any) string { + ns.logger.Warnidf(id, format, args...) + return "" +} + // Warnmf is epxermimental and subject to change at any time. func (ns *Namespace) Warnmf(m any, format string, args ...any) string { return ns.logmf(ns.logger.Warn(), m, format, args...) diff --git a/tpl/fmt/fmt_integration_test.go b/tpl/fmt/fmt_integration_test.go index 40bfefcdc4e..74322770e08 100644 --- a/tpl/fmt/fmt_integration_test.go +++ b/tpl/fmt/fmt_integration_test.go @@ -16,6 +16,7 @@ package fmt_test import ( "testing" + qt "github.com/frankban/quicktest" "github.com/gohugoio/hugo/hugolib" ) @@ -32,13 +33,25 @@ ignoreErrors = ['error-b'] {{ erroridf "error-b" "%s" "b"}} ` - b := hugolib.NewIntegrationTestBuilder( - hugolib.IntegrationTestConfig{ - T: t, - TxtarString: files, - }, - ) + b, err := hugolib.TestE(t, files) - b.BuildE() - b.AssertLogMatches(`^ERROR a\nYou can suppress this error by adding the following to your site configuration:\nignoreErrors = \['error-a'\]\n$`) + b.Assert(err, qt.IsNotNil) + b.AssertLogMatches(`^ERROR a\nYou can suppress this error by adding the following to your site configuration:\nignoreLogs = \['error-a'\]\n$`) +} + +func TestWarnidf(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.toml -- +disableKinds = ['page','rss','section','sitemap','taxonomy','term'] +ignoreLogs = ['warning-b'] +-- layouts/index.html -- +{{ warnidf "warning-a" "%s" "a"}} +{{ warnidf "warning-b" "%s" "b"}} + ` + + b := hugolib.Test(t, files, hugolib.TestOptWarn()) + b.AssertLogContains("WARN a", "You can suppress this warning", "ignoreLogs", "['warning-a']") + b.AssertLogNotContains("['warning-b']") } diff --git a/tpl/fmt/init.go b/tpl/fmt/init.go index 8000627e211..701bd3b6a6a 100644 --- a/tpl/fmt/init.go +++ b/tpl/fmt/init.go @@ -66,6 +66,13 @@ func init() { }, ) + ns.AddMethodMapping(ctx.Warnidf, + []string{"warnidf"}, + [][2]string{ + {`{{ warnidf "my-warn-id" "%s." "warning" }}`, ``}, + }, + ) + ns.AddMethodMapping(ctx.Warnf, []string{"warnf"}, [][2]string{