diff --git a/build/package/nfpm/config/dfget.yaml b/build/package/nfpm/config/dfget.yaml index 304fa0160..23a749ab9 100644 --- a/build/package/nfpm/config/dfget.yaml +++ b/build/package/nfpm/config/dfget.yaml @@ -26,6 +26,7 @@ scheduler: # when enabled, pprof will be enabled, verbose: true +log-level: debug console: false # current host info used for scheduler diff --git a/cmd/dependency/base/option.go b/cmd/dependency/base/option.go index 3dc9c4649..62dd344b1 100644 --- a/cmd/dependency/base/option.go +++ b/cmd/dependency/base/option.go @@ -19,6 +19,7 @@ package base type Options struct { Console bool `yaml:"console" mapstructure:"console"` Verbose bool `yaml:"verbose" mapstructure:"verbose"` + LogLevel string `yaml:"log-level" mapstructure:"log-level"` PProfPort int `yaml:"pprof-port" mapstructure:"pprof-port"` Tracing TracingConfig `yaml:"tracing" mapstructure:"tracing"` } diff --git a/cmd/dependency/dependency.go b/cmd/dependency/dependency.go index 736fbefa9..9ca2ab199 100644 --- a/cmd/dependency/dependency.go +++ b/cmd/dependency/dependency.go @@ -72,6 +72,7 @@ func InitCommandAndConfig(cmd *cobra.Command, useConfigFile bool, config any) { flags := cmd.PersistentFlags() flags.Bool("console", false, "whether logger output records to the stdout") flags.Bool("verbose", false, "whether logger use debug level") + flags.String("log-level", "", "use specific log level(debug, info, warn, error), take precedence over verbose flag") flags.Int("pprof-port", -1, "listen port for pprof, 0 represents random port") flags.String("config", "", fmt.Sprintf("the path of configuration file with yaml extension name, default is %s, it can also be set by env var: %s", filepath.Join(dfpath.DefaultConfigDir, rootName+".yaml"), strings.ToUpper(rootName+"_config"))) diff --git a/cmd/dfcache/cmd/root.go b/cmd/dfcache/cmd/root.go index 5e1e03d60..391994ea4 100644 --- a/cmd/dfcache/cmd/root.go +++ b/cmd/dfcache/cmd/root.go @@ -142,7 +142,7 @@ func runDfcacheSubcmd(ctx context.Context, cmdName string, args []string) error MaxBackups: dfcacheConfig.LogMaxBackups} // Initialize logger - if err := logger.InitDfcache(dfcacheConfig.Console, d.LogDir(), rotateConfig); err != nil { + if err := logger.InitDfcache(dfcacheConfig.Verbose, dfcacheConfig.LogLevel, d.LogDir(), rotateConfig); err != nil { return fmt.Errorf("init client dfcache logger: %w", err) } logger.Infof("version:\n%s", version.Version()) diff --git a/cmd/dfget/cmd/daemon.go b/cmd/dfget/cmd/daemon.go index cbc1db0e6..b0d7a7797 100644 --- a/cmd/dfget/cmd/daemon.go +++ b/cmd/dfget/cmd/daemon.go @@ -47,8 +47,8 @@ var ( var daemonCmd = &cobra.Command{ Use: "daemon", Short: "start the client daemon of dragonfly", - Long: `client daemon is mainly responsible for transmitting blocks between peers -and putting the completed file into the specified target path. at the same time, + Long: `client daemon is mainly responsible for transmitting blocks between peers +and putting the completed file into the specified target path. at the same time, it supports container engine, wget and other downloading tools through proxy function.`, Args: cobra.NoArgs, DisableAutoGenTag: true, @@ -80,7 +80,7 @@ it supports container engine, wget and other downloading tools through proxy fun MaxBackups: cfg.LogMaxBackups} // Initialize logger - if err := logger.InitDaemon(cfg.Verbose, cfg.Console, d.LogDir(), rotateConfig); err != nil { + if err := logger.InitDaemon(cfg.Verbose, cfg.LogLevel, cfg.Console, d.LogDir(), rotateConfig); err != nil { return fmt.Errorf("init client daemon logger: %w", err) } logger.RedirectStdoutAndStderr(cfg.Console, path.Join(d.LogDir(), types.DaemonName)) diff --git a/cmd/dfget/cmd/root.go b/cmd/dfget/cmd/root.go index 619a9362a..21e556cc2 100644 --- a/cmd/dfget/cmd/root.go +++ b/cmd/dfget/cmd/root.go @@ -94,7 +94,7 @@ var rootCmd = &cobra.Command{ MaxBackups: dfgetConfig.LogMaxBackups} // Initialize logger - if err := logger.InitDfget(dfgetConfig.Verbose, dfgetConfig.Console, d.LogDir(), rotateConfig); err != nil { + if err := logger.InitDfget(dfgetConfig.Verbose, dfgetConfig.LogLevel, dfgetConfig.Console, d.LogDir(), rotateConfig); err != nil { return fmt.Errorf("init client dfget logger: %w", err) } diff --git a/cmd/manager/cmd/root.go b/cmd/manager/cmd/root.go index d085c5190..041b6873d 100644 --- a/cmd/manager/cmd/root.go +++ b/cmd/manager/cmd/root.go @@ -41,7 +41,7 @@ var ( var rootCmd = &cobra.Command{ Use: "manager", Short: "The central manager of dragonfly.", - Long: `manager is a long-running process and is mainly responsible + Long: `manager is a long-running process and is mainly responsible for managing schedulers and seed peers, offering http apis and portal, etc.`, Args: cobra.NoArgs, DisableAutoGenTag: true, @@ -72,7 +72,7 @@ for managing schedulers and seed peers, offering http apis and portal, etc.`, MaxBackups: cfg.Server.LogMaxBackups} // Initialize logger. - if err := logger.InitManager(cfg.Verbose, cfg.Console, d.LogDir(), rotateConfig); err != nil { + if err := logger.InitManager(cfg.Verbose, cfg.LogLevel, cfg.Console, d.LogDir(), rotateConfig); err != nil { return fmt.Errorf("init manager logger: %w", err) } logger.RedirectStdoutAndStderr(cfg.Console, path.Join(d.LogDir(), types.ManagerName)) diff --git a/cmd/scheduler/cmd/root.go b/cmd/scheduler/cmd/root.go index 0647b3a41..fa198290a 100644 --- a/cmd/scheduler/cmd/root.go +++ b/cmd/scheduler/cmd/root.go @@ -41,7 +41,7 @@ var ( var rootCmd = &cobra.Command{ Use: "scheduler", Short: "the scheduler of dragonfly", - Long: `Scheduler is a long-running process which receives and manages download tasks from the dfdaemon, notify the seed peer to return to the source, + Long: `Scheduler is a long-running process which receives and manages download tasks from the dfdaemon, notify the seed peer to return to the source, generate and maintain a P2P network during the download process, and push suitable download nodes to the dfdaemon`, Args: cobra.NoArgs, DisableAutoGenTag: true, @@ -72,7 +72,7 @@ generate and maintain a P2P network during the download process, and push suitab MaxBackups: cfg.Server.LogMaxBackups} // Initialize logger. - if err := logger.InitScheduler(cfg.Verbose, cfg.Console, d.LogDir(), rotateConfig); err != nil { + if err := logger.InitScheduler(cfg.Verbose, cfg.LogLevel, cfg.Console, d.LogDir(), rotateConfig); err != nil { return fmt.Errorf("init scheduler logger: %w", err) } logger.RedirectStdoutAndStderr(cfg.Console, path.Join(d.LogDir(), types.SchedulerName)) diff --git a/deploy/docker-compose/template/manager.template.yaml b/deploy/docker-compose/template/manager.template.yaml index db603a8ce..6ff0cf7a0 100644 --- a/deploy/docker-compose/template/manager.template.yaml +++ b/deploy/docker-compose/template/manager.template.yaml @@ -165,6 +165,9 @@ console: false # Whether to enable debug level logger and enable pprof. verbose: true +# Use specific log level(debug, info, warn, error), take precedence over verbose flag. +# log-level: debug + # Listen port for pprof, only valid when the verbose option is true, default is -1. pprof-port: -1 diff --git a/deploy/docker-compose/template/scheduler.template.yaml b/deploy/docker-compose/template/scheduler.template.yaml index 8abebbc94..830d8b904 100644 --- a/deploy/docker-compose/template/scheduler.template.yaml +++ b/deploy/docker-compose/template/scheduler.template.yaml @@ -181,6 +181,9 @@ console: false # Whether to enable debug level logger and enable pprof. verbose: true +# Use specific log level(debug, info, warn, error), take precedence over verbose flag. +# log-level: debug + # Listen port for pprof, only valid when the verbose option is true, default is -1. pprof-port: -1 diff --git a/internal/dflog/logcore.go b/internal/dflog/logcore.go index e9371409f..7e53ce65f 100644 --- a/internal/dflog/logcore.go +++ b/internal/dflog/logcore.go @@ -17,6 +17,7 @@ package logger import ( + "fmt" "strings" "go.uber.org/atomic" @@ -52,7 +53,7 @@ var customCoreLevel atomic.Bool var grpcLevel = zap.NewAtomicLevelAt(zapcore.WarnLevel) var customGrpcLevel atomic.Bool -func CreateLogger(filePath string, compress bool, stats bool, verbose bool, config LogRotateConfig) (*zap.Logger, zap.AtomicLevel, error) { +func CreateLogger(filePath string, compress bool, stats bool, verbose bool, logLevel string, config LogRotateConfig) (*zap.Logger, zap.AtomicLevel, error) { rotateConfig := &lumberjack.Logger{ Filename: filePath, @@ -66,10 +67,25 @@ func CreateLogger(filePath string, compress bool, stats bool, verbose bool, conf encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(encodeTimeFormat) - var level = zap.NewAtomicLevel() - if verbose { + var level = zap.NewAtomicLevelAt(zap.InfoLevel) + // Use logLevel first, then fallback to verbose flag. + if logLevel != "" { + switch strings.ToLower(logLevel) { + case "debug": + level = zap.NewAtomicLevelAt(zapcore.DebugLevel) + case "info": + level = zap.NewAtomicLevelAt(zapcore.InfoLevel) + case "warn": + level = zap.NewAtomicLevelAt(zapcore.WarnLevel) + case "error": + level = zap.NewAtomicLevelAt(zapcore.ErrorLevel) + default: + fmt.Printf("Warning: invalid log level '%s', using 'info' instead\n", logLevel) + } + } else if verbose { level = zap.NewAtomicLevelAt(zapcore.DebugLevel) } + if strings.HasSuffix(filePath, GrpcLogFileName) && customGrpcLevel.Load() { level = grpcLevel } else if strings.HasSuffix(filePath, CoreLogFileName) && customCoreLevel.Load() { diff --git a/internal/dflog/loginit.go b/internal/dflog/loginit.go index c3dc16489..5fee7c881 100644 --- a/internal/dflog/loginit.go +++ b/internal/dflog/loginit.go @@ -17,10 +17,12 @@ package logger import ( + "fmt" "io/fs" "os" "path" "path/filepath" + "strings" "go.uber.org/zap" @@ -33,9 +35,9 @@ type logInitMeta struct { setLoggerFunc func(log *zap.Logger) } -func InitManager(verbose, console bool, dir string, rotateConfig LogRotateConfig) error { +func InitManager(verbose bool, logLevel string, console bool, dir string, rotateConfig LogRotateConfig) error { if console { - return createConsoleLogger(verbose) + return createConsoleLogger(verbose, logLevel) } logDir := filepath.Join(dir, types.ManagerName) @@ -62,12 +64,12 @@ func InitManager(verbose, console bool, dir string, rotateConfig LogRotateConfig }, } - return createFileLogger(verbose, meta, logDir, rotateConfig) + return createFileLogger(verbose, logLevel, meta, logDir, rotateConfig) } -func InitScheduler(verbose, console bool, dir string, rotateConfig LogRotateConfig) error { +func InitScheduler(verbose bool, logLevel string, console bool, dir string, rotateConfig LogRotateConfig) error { if console { - return createConsoleLogger(verbose) + return createConsoleLogger(verbose, logLevel) } logDir := filepath.Join(dir, types.SchedulerName) @@ -90,12 +92,12 @@ func InitScheduler(verbose, console bool, dir string, rotateConfig LogRotateConf }, } - return createFileLogger(verbose, meta, logDir, rotateConfig) + return createFileLogger(verbose, logLevel, meta, logDir, rotateConfig) } -func InitDaemon(verbose, console bool, dir string, rotateConfig LogRotateConfig) error { +func InitDaemon(verbose bool, logLevel string, console bool, dir string, rotateConfig LogRotateConfig) error { if console { - return createConsoleLogger(verbose) + return createConsoleLogger(verbose, logLevel) } logDir := filepath.Join(dir, types.DaemonName) @@ -118,12 +120,12 @@ func InitDaemon(verbose, console bool, dir string, rotateConfig LogRotateConfig) }, } - return createFileLogger(verbose, meta, logDir, rotateConfig) + return createFileLogger(verbose, logLevel, meta, logDir, rotateConfig) } -func InitDfget(verbose, console bool, dir string, rotateConfig LogRotateConfig) error { +func InitDfget(verbose bool, logLevel string, console bool, dir string, rotateConfig LogRotateConfig) error { if console { - return createConsoleLogger(verbose) + return createConsoleLogger(verbose, logLevel) } logDir := filepath.Join(dir, types.DfgetName) @@ -138,10 +140,10 @@ func InitDfget(verbose, console bool, dir string, rotateConfig LogRotateConfig) }, } - return createFileLogger(verbose, meta, logDir, rotateConfig) + return createFileLogger(verbose, logLevel, meta, logDir, rotateConfig) } -func InitDfcache(console bool, dir string, rotateConfig LogRotateConfig) error { +func InitDfcache(verbose bool, logLevel string, dir string, rotateConfig LogRotateConfig) error { logDir := filepath.Join(dir, types.DfcacheName) var meta = []logInitMeta{ { @@ -154,16 +156,31 @@ func InitDfcache(console bool, dir string, rotateConfig LogRotateConfig) error { }, } - return createFileLogger(console, meta, logDir, rotateConfig) + return createFileLogger(verbose, logLevel, meta, logDir, rotateConfig) } -func createConsoleLogger(verbose bool) error { +func createConsoleLogger(verbose bool, logLevel string) error { levels = nil config := zap.NewDevelopmentConfig() config.Level = zap.NewAtomicLevelAt(zap.InfoLevel) - if verbose { + // Use logLevel first, then fallback to verbose flag. + if logLevel != "" { + switch strings.ToLower(logLevel) { + case "debug": + config.Level = zap.NewAtomicLevelAt(zap.DebugLevel) + case "info": + config.Level = zap.NewAtomicLevelAt(zap.InfoLevel) + case "warn": + config.Level = zap.NewAtomicLevelAt(zap.WarnLevel) + case "error": + config.Level = zap.NewAtomicLevelAt(zap.ErrorLevel) + default: + fmt.Printf("Warning: invalid log level '%s', using 'info' instead\n", logLevel) + } + } else if verbose { config.Level = zap.NewAtomicLevelAt(zap.DebugLevel) } + log, err := config.Build(zap.AddCaller(), zap.AddStacktrace(zap.WarnLevel), zap.AddCallerSkip(1)) if err == nil { sugar := log.Sugar() @@ -182,13 +199,13 @@ func createConsoleLogger(verbose bool) error { return nil } -func createFileLogger(verbose bool, meta []logInitMeta, logDir string, rotateConfig LogRotateConfig) error { +func createFileLogger(verbose bool, logLevel string, meta []logInitMeta, logDir string, rotateConfig LogRotateConfig) error { levels = nil // create parent dir first _ = os.MkdirAll(logDir, fs.FileMode(0700)) for _, m := range meta { - log, level, err := CreateLogger(path.Join(logDir, m.fileName), false, false, verbose, rotateConfig) + log, level, err := CreateLogger(path.Join(logDir, m.fileName), false, false, verbose, logLevel, rotateConfig) if err != nil { return err } diff --git a/pkg/log/log.go b/pkg/log/log.go index bdb91751b..7559c3b2b 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -34,7 +34,7 @@ func SetGrpcLevel(level zapcore.Level) { } // SetupDaemon sets daemon log config: path, console -func SetupDaemon(logDir string, verbose bool, console bool, rotateConfig logger.LogRotateConfig) error { +func SetupDaemon(logDir string, verbose bool, logLevel string, console bool, rotateConfig logger.LogRotateConfig) error { var options []dfpath.Option if logDir != "" { options = append(options, dfpath.WithLogDir(logDir)) @@ -45,5 +45,5 @@ func SetupDaemon(logDir string, verbose bool, console bool, rotateConfig logger. return err } - return logger.InitDaemon(verbose, console, d.LogDir(), rotateConfig) + return logger.InitDaemon(verbose, logLevel, console, d.LogDir(), rotateConfig) } diff --git a/scheduler/resource/standard/peer_manager.go b/scheduler/resource/standard/peer_manager.go index 3ffece3bb..b377885b3 100644 --- a/scheduler/resource/standard/peer_manager.go +++ b/scheduler/resource/standard/peer_manager.go @@ -212,7 +212,7 @@ func (p *peerManager) RunGC(ctx context.Context) error { if elapsed > p.hostTTL { peer.Log.Info("peer elapsed exceeds the host ttl, causing the peer to leave") if err := peer.FSM.Event(ctx, PeerEventLeave); err != nil { - peer.Log.Errorf("peer fsm event failed: %s", err.Error()) + peer.Log.Infof("peer fsm event failed: %s", err.Error()) return true }