diff --git a/.golangci.yml b/.golangci.yml index 68622529d..b01f89405 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -101,9 +101,9 @@ linters: - Print - Printf - Warn - - Warnf - Fatal - Fatalf + - LazySprintf misspell: locale: US ignore-rules: diff --git a/cmd/cmd_renew.go b/cmd/cmd_renew.go index 5176d3110..aff22372d 100644 --- a/cmd/cmd_renew.go +++ b/cmd/cmd_renew.go @@ -382,7 +382,7 @@ func needRenewal(x509Cert *x509.Certificate, domain string, days int, dynamic bo return true } - log.Info(fmt.Sprintf("Skip renewal: the certificate expires in %d days, the number of days defined to perform the renewal is %d.", + log.Infof(log.LazySprintf("Skip renewal: the certificate expires in %d days, the number of days defined to perform the renewal is %d.", notAfter, days), "domain", domain) return false @@ -402,7 +402,7 @@ func needRenewalDynamic(x509Cert *x509.Certificate, domain string, now time.Time return true } - log.Info(fmt.Sprintf("Skip renewal: The certificate expires at %s, the renewal can be performed in %s.", + log.Infof(log.LazySprintf("Skip renewal: The certificate expires at %s, the renewal can be performed in %s.", x509Cert.NotAfter.Format(time.RFC3339), dueDate.Sub(now)), "domain", domain) return false diff --git a/cmd/setup.go b/cmd/setup.go index 0460e1f18..9ff5804b6 100644 --- a/cmd/setup.go +++ b/cmd/setup.go @@ -202,7 +202,7 @@ func checkRetry(ctx context.Context, resp *http.Response, err error) (bool, erro } default: - log.Warn(fmt.Sprintf("retry: %v", errorDetails)) + log.Warnf(log.LazySprintf("retry: %v", errorDetails)) return rt, errorDetails } diff --git a/cmd/setup_challenges.go b/cmd/setup_challenges.go index d7b6e453d..6f7fce708 100644 --- a/cmd/setup_challenges.go +++ b/cmd/setup_challenges.go @@ -170,7 +170,7 @@ func setupDNS(ctx *cli.Context, client *lego.Client) error { func checkPropagationExclusiveOptions(ctx *cli.Context) error { if ctx.IsSet(flgDNSDisableCP) { - log.Warn(fmt.Sprintf("The flag '%s' is deprecated use '%s' instead.", flgDNSDisableCP, flgDNSPropagationDisableANS)) + log.Warnf(log.LazySprintf("The flag '%s' is deprecated use '%s' instead.", flgDNSDisableCP, flgDNSPropagationDisableANS)) } if (isSetBool(ctx, flgDNSDisableCP) || isSetBool(ctx, flgDNSPropagationDisableANS)) && ctx.IsSet(flgDNSPropagationWait) { diff --git a/log/lazy.go b/log/lazy.go new file mode 100644 index 000000000..037340784 --- /dev/null +++ b/log/lazy.go @@ -0,0 +1,51 @@ +package log + +import ( + "context" + "fmt" + "log/slog" +) + +type LazyMessage struct { + msg string + args []any +} + +func LazySprintf(msg string, args ...any) LazyMessage { + return LazyMessage{ + msg: msg, + args: args, + } +} + +func (l LazyMessage) String() string { + return fmt.Sprintf(l.msg, l.args...) +} + +// Debugf calls [Logger.Debug] on the default logger. +func Debugf(msg LazyMessage, args ...any) { + logLazy(slog.LevelDebug, msg, args...) +} + +// Infof calls [Logger.Info] on the default logger. +func Infof(msg LazyMessage, args ...any) { + logLazy(slog.LevelInfo, msg, args...) +} + +// Warnf calls [Logger.Warn] on the default logger. +func Warnf(msg LazyMessage, args ...any) { + logLazy(slog.LevelWarn, msg, args...) +} + +// Errorf calls [Logger.Error] on the default logger. +func Errorf(msg LazyMessage, args ...any) { + logLazy(slog.LevelError, msg, args...) +} + +func logLazy(level slog.Level, msg LazyMessage, args ...any) { + ctx := context.Background() + + if Default().Enabled(ctx, level) { + Default().Log(ctx, level, msg.String(), args...) + } +} diff --git a/platform/wait/wait.go b/platform/wait/wait.go index baa887cd1..2ae35cb72 100644 --- a/platform/wait/wait.go +++ b/platform/wait/wait.go @@ -11,7 +11,7 @@ import ( // For polls the given function 'f', once every 'interval', up to 'timeout'. func For(msg string, timeout, interval time.Duration, f func() (bool, error)) error { - log.Info(fmt.Sprintf("Wait for %s.", msg), "timeout", timeout, "interval", interval) + log.Infof(log.LazySprintf("Wait for %s.", msg), "timeout", timeout, "interval", interval) var lastErr error diff --git a/providers/dns/cloudns/cloudns.go b/providers/dns/cloudns/cloudns.go index 69ad6c95e..651c6756f 100644 --- a/providers/dns/cloudns/cloudns.go +++ b/providers/dns/cloudns/cloudns.go @@ -176,7 +176,7 @@ func (d *DNSProvider) waitNameservers(ctx context.Context, domain string, zone * return fmt.Errorf("nameserver sync on %s: %w", domain, err) } - log.Info(fmt.Sprintf("Sync %d/%d complete", syncProgress.Updated, syncProgress.Total), "domain", domain) + log.Infof(log.LazySprintf("Sync %d/%d complete", syncProgress.Updated, syncProgress.Total), "domain", domain) if !syncProgress.Complete { return fmt.Errorf("nameserver sync on %s not complete", domain) diff --git a/providers/dns/hetzner/hetzner.go b/providers/dns/hetzner/hetzner.go index 33b3344df..c3410c1c9 100644 --- a/providers/dns/hetzner/hetzner.go +++ b/providers/dns/hetzner/hetzner.go @@ -3,7 +3,6 @@ package hetzner import ( "errors" - "fmt" "net/http" "time" @@ -119,7 +118,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { return &DNSProvider{provider: provider}, nil case config.APIKey != "": - log.Warn(fmt.Sprintf("%s (legacy Hetzner DNS API) is deprecated, please use %s (Hetzner Cloud API) instead.", EnvAPIKey, EnvAPIToken)) + log.Warnf(log.LazySprintf("%s (legacy Hetzner DNS API) is deprecated, please use %s (Hetzner Cloud API) instead.", EnvAPIKey, EnvAPIToken)) cfg := &legacy.Config{ APIKey: config.APIKey, diff --git a/providers/dns/namecheap/namecheap.go b/providers/dns/namecheap/namecheap.go index 4d13e17ba..8abedaa49 100644 --- a/providers/dns/namecheap/namecheap.go +++ b/providers/dns/namecheap/namecheap.go @@ -164,7 +164,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { records = append(records, record) for _, h := range records { - log.Debug(fmt.Sprintf("%-5.5s %-30.30s %-6s %-70.70s", h.Type, h.Name, h.TTL, h.Address)) + log.Debugf(log.LazySprintf("%-5.5s %-30.30s %-6s %-70.70s", h.Type, h.Name, h.TTL, h.Address)) } err = d.client.SetHosts(ctx, pr.sld, pr.tld, records)