diff --git a/fs/log.go b/fs/log.go index 77fc6a521..dcd726eec 100644 --- a/fs/log.go +++ b/fs/log.go @@ -12,6 +12,10 @@ import ( "github.com/rclone/rclone/lib/caller" ) +// logger represents the slog logging facility and should be overridden by +// the fs/log handling code. +var logger *slog.Logger = slog.Default() + // LogLevel describes rclone's logs. These are a subset of the syslog log levels. type LogLevel = Enum[logLevelChoices] @@ -137,7 +141,7 @@ func LogLevelToSlog(level LogLevel) slog.Level { } func logSlog(level LogLevel, text string, attrs []any) { - slog.Log(context.Background(), LogLevelToSlog(level), text, attrs...) + logger.Log(context.Background(), LogLevelToSlog(level), text, attrs...) } func logSlogWithObject(level LogLevel, o any, text string, attrs []any) { @@ -337,3 +341,8 @@ func PrettyPrint(in any, label string, level LogLevel) { } LogPrintf(level, label, "\n%s\n", string(inBytes)) } + +// SetLogger overrides the slog logger using the specified handler +func SetLogger(h slog.Handler) { + logger = slog.New(h) +} diff --git a/fs/log/log.go b/fs/log/log.go index 76f1f6b0e..8f1896633 100644 --- a/fs/log/log.go +++ b/fs/log/log.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "io" + "log/slog" "os" "reflect" "runtime" @@ -201,7 +202,21 @@ func init() { } // InitLogging start the logging as per the command line flags +// +// This is called explicitly from the CLI, the librclone wrapper and +// the test framework, but not from package init, so that importing +// rclone as a library has no side effects on the process-wide default +// slog logger. func InitLogging() { + // Redirect the process-wide default logger through rclone's + // handler so that log.Print/log.Fatal and slog.Default() (used by + // some standard library and third party code) end up in rclone's + // log output. + slog.SetDefault(slog.New(Handler)) + + // Make log.Printf logs at level Notice + slog.SetLogLoggerLevel(fs.SlogLevelNotice) + // Note that ci only has the defaults in at this point // We set real values in logReload ci := fs.GetConfig(context.Background()) diff --git a/fs/log/slog.go b/fs/log/slog.go index b5e3c34ff..a006f94a1 100644 --- a/fs/log/slog.go +++ b/fs/log/slog.go @@ -27,6 +27,12 @@ var Handler = defaultHandler() // This will be adjusted by InitLogging to be the configured levels // but it is important we have a logger running regardless of whether // InitLogging has been called yet or not. +// +// Note that this only sets rclone's private logger via fs.SetLogger +// so that importing this package has no side effects on the +// process-wide default slog logger. The CLI and other rclone-as-a- +// program entry points pick up the default logger redirection in +// InitLogging instead. func defaultHandler() *OutputHandler { // Default options for default handler opts := &slog.HandlerOptions{ @@ -36,11 +42,8 @@ func defaultHandler() *OutputHandler { // Create our handler h := NewOutputHandler(os.Stderr, opts, logFormatDate|logFormatTime) - // Set the slog default handler - slog.SetDefault(slog.New(h)) - - // Make log.Printf logs at level Notice - slog.SetLogLoggerLevel(fs.SlogLevelNotice) + // Set rclone's internal logger so rclone logging works + fs.SetLogger(h) return h }