forked from TrueCloudLab/rclone
Redo log level flags
* -vv or --log-level DEBUG * -v or --log-level INFO * --log-level NOTICE (default) * -q --log-level ERROR Replace Config.Verbose and Config.Quiet with Config.LogLevel Fixes #739 Fixes #1108 Fixes #1000
This commit is contained in:
parent
0366ea39c5
commit
ac1c041377
9 changed files with 137 additions and 40 deletions
|
@ -274,12 +274,10 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to %s: %v", cmd.Name(), err)
|
log.Fatalf("Failed to %s: %v", cmd.Name(), err)
|
||||||
}
|
}
|
||||||
if showStats && (!fs.Config.Quiet || fs.Stats.Errored() || *statsInterval > 0) {
|
if showStats && (fs.Stats.Errored() || *statsInterval > 0) {
|
||||||
fs.Infof(nil, "%s", fs.Stats)
|
fs.Infof(nil, "%s", fs.Stats)
|
||||||
}
|
}
|
||||||
if fs.Config.Verbose {
|
fs.Debugf(nil, "Go routines at exit %d\n", runtime.NumGoroutine())
|
||||||
fs.Debugf(nil, "Go routines at exit %d\n", runtime.NumGoroutine())
|
|
||||||
}
|
|
||||||
if fs.Stats.Errored() {
|
if fs.Stats.Errored() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,8 +71,9 @@ func newRun() *Run {
|
||||||
// "RCLONE_CONFIG_PASS=hunter2" (or your password)
|
// "RCLONE_CONFIG_PASS=hunter2" (or your password)
|
||||||
*fs.AskPassword = false
|
*fs.AskPassword = false
|
||||||
fs.LoadConfig()
|
fs.LoadConfig()
|
||||||
fs.Config.Verbose = *Verbose
|
if *Verbose {
|
||||||
fs.Config.Quiet = !*Verbose
|
fs.Config.LogLevel = fs.LogLevelDebug
|
||||||
|
}
|
||||||
fs.Config.DumpHeaders = *DumpHeaders
|
fs.Config.DumpHeaders = *DumpHeaders
|
||||||
fs.Config.DumpBodies = *DumpBodies
|
fs.Config.DumpBodies = *DumpBodies
|
||||||
fs.Config.LowLevelRetries = *LowLevelRetries
|
fs.Config.LowLevelRetries = *LowLevelRetries
|
||||||
|
|
|
@ -362,6 +362,22 @@ This can be useful for tracking down problems with syncs in
|
||||||
combination with the `-v` flag. See the Logging section for more
|
combination with the `-v` flag. See the Logging section for more
|
||||||
info.
|
info.
|
||||||
|
|
||||||
|
### --log-level LEVEL ###
|
||||||
|
|
||||||
|
This sets the log level for rclone. The default log level is `INFO`.
|
||||||
|
|
||||||
|
`DEBUG` is equivalent to `-vv`. It outputs lots of debug info - useful
|
||||||
|
for bug reports and really finding out what rclone is doing.
|
||||||
|
|
||||||
|
`INFO` is equivalent to `-v`. It outputs information about each transfer
|
||||||
|
and prints stats once a minute by default.
|
||||||
|
|
||||||
|
`NOTICE` is the default log level if no logging flags are supplied. It
|
||||||
|
outputs very little when things are working normally. It outputs
|
||||||
|
warnings and significant events.
|
||||||
|
|
||||||
|
`ERROR` is equivalent to `-q`. It only output error messages.
|
||||||
|
|
||||||
### --low-level-retries NUMBER ###
|
### --low-level-retries NUMBER ###
|
||||||
|
|
||||||
This controls the number of low level retries rclone does.
|
This controls the number of low level retries rclone does.
|
||||||
|
@ -568,12 +584,14 @@ This can be useful when transferring to a remote which doesn't support
|
||||||
mod times directly as it is more accurate than a `--size-only` check
|
mod times directly as it is more accurate than a `--size-only` check
|
||||||
and faster than using `--checksum`.
|
and faster than using `--checksum`.
|
||||||
|
|
||||||
### -v, --verbose ###
|
### -v, -vv, --verbose ###
|
||||||
|
|
||||||
If you set this flag, rclone will become very verbose telling you
|
With `-v` rclone will tell you about each file that is transferred and
|
||||||
about every file it considers and transfers.
|
a small number of significant events.
|
||||||
|
|
||||||
Very useful for debugging.
|
With `-vv` rclone will become very verbose telling you about every
|
||||||
|
file it considers and transfers. Please send bug reports with a log
|
||||||
|
with this setting.
|
||||||
|
|
||||||
### -V, --version ###
|
### -V, --version ###
|
||||||
|
|
||||||
|
@ -762,22 +780,34 @@ See the [filtering section](/filtering/).
|
||||||
Logging
|
Logging
|
||||||
-------
|
-------
|
||||||
|
|
||||||
rclone has 3 levels of logging, `Error`, `Info` and `Debug`.
|
rclone has 4 levels of logging, `Error`, `Notice`, `Info` and `Debug`.
|
||||||
|
|
||||||
By default rclone logs `Error` and `Info` to standard error and `Debug`
|
By default rclone logs to standard error. This means you can redirect
|
||||||
to standard output. This means you can redirect standard output and
|
standard error and still see the normal output of rclone commands (eg
|
||||||
standard error to different places.
|
`rclone ls`).
|
||||||
|
|
||||||
By default rclone will produce `Error` and `Info` level messages.
|
By default rclone will produce `Error` and `Notice` level messages.
|
||||||
|
|
||||||
If you use the `-q` flag, rclone will only produce `Error` messages.
|
If you use the `-q` flag, rclone will only produce `Error` messages.
|
||||||
|
|
||||||
If you use the `-v` flag, rclone will produce `Error`, `Info` and
|
If you use the `-v` flag, rclone will produce `Error`, `Notice` and
|
||||||
`Debug` messages.
|
`Info` messages.
|
||||||
|
|
||||||
|
If you use the `-vv` flag, rclone will produce `Error`, `Notice`,
|
||||||
|
`Info` and `Debug` messages.
|
||||||
|
|
||||||
|
You can also control the log levels with the `--log-level` flag.
|
||||||
|
|
||||||
If you use the `--log-file=FILE` option, rclone will redirect `Error`,
|
If you use the `--log-file=FILE` option, rclone will redirect `Error`,
|
||||||
`Info` and `Debug` messages along with standard error to FILE.
|
`Info` and `Debug` messages along with standard error to FILE.
|
||||||
|
|
||||||
|
If you use the `--syslog` flag then rclone will log to syslog and the
|
||||||
|
`--syslog-facility` control which facility it uses.
|
||||||
|
|
||||||
|
Rclone prefixes all log messages with their level in capitals, eg INFO
|
||||||
|
which makes it easy to grep the log file for different kinds of
|
||||||
|
information.
|
||||||
|
|
||||||
Exit Code
|
Exit Code
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
|
42
fs/config.go
42
fs/config.go
|
@ -26,6 +26,7 @@ import (
|
||||||
|
|
||||||
"github.com/Unknwon/goconfig"
|
"github.com/Unknwon/goconfig"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
"golang.org/x/crypto/nacl/secretbox"
|
"golang.org/x/crypto/nacl/secretbox"
|
||||||
"golang.org/x/text/unicode/norm"
|
"golang.org/x/text/unicode/norm"
|
||||||
)
|
)
|
||||||
|
@ -56,8 +57,9 @@ var (
|
||||||
// Config is the global config
|
// Config is the global config
|
||||||
Config = &ConfigInfo{}
|
Config = &ConfigInfo{}
|
||||||
// Flags
|
// Flags
|
||||||
verbose = BoolP("verbose", "v", false, "Print lots more stuff")
|
verbose = CountP("verbose", "v", "Print lots more stuff (repeat for more)")
|
||||||
quiet = BoolP("quiet", "q", false, "Print as little stuff as possible")
|
quiet = BoolP("quiet", "q", false, "Print as little stuff as possible")
|
||||||
|
logLevel = StringP("log-level", "", "INFO", "Log level DEBUG|INFO|NOTICE|ERROR")
|
||||||
modifyWindow = DurationP("modify-window", "", time.Nanosecond, "Max time diff to be considered the same")
|
modifyWindow = DurationP("modify-window", "", time.Nanosecond, "Max time diff to be considered the same")
|
||||||
checkers = IntP("checkers", "", 8, "Number of checkers to run in parallel.")
|
checkers = IntP("checkers", "", 8, "Number of checkers to run in parallel.")
|
||||||
transfers = IntP("transfers", "", 4, "Number of file transfers to run in parallel.")
|
transfers = IntP("transfers", "", 4, "Number of file transfers to run in parallel.")
|
||||||
|
@ -182,8 +184,7 @@ func MustReveal(x string) string {
|
||||||
|
|
||||||
// ConfigInfo is filesystem config options
|
// ConfigInfo is filesystem config options
|
||||||
type ConfigInfo struct {
|
type ConfigInfo struct {
|
||||||
Verbose bool
|
LogLevel LogLevel
|
||||||
Quiet bool
|
|
||||||
DryRun bool
|
DryRun bool
|
||||||
CheckSum bool
|
CheckSum bool
|
||||||
SizeOnly bool
|
SizeOnly bool
|
||||||
|
@ -300,8 +301,39 @@ func LoadConfig() {
|
||||||
// Read some flags if set
|
// Read some flags if set
|
||||||
//
|
//
|
||||||
// FIXME read these from the config file too
|
// FIXME read these from the config file too
|
||||||
Config.Verbose = *verbose
|
Config.LogLevel = LogLevelNotice
|
||||||
Config.Quiet = *quiet
|
if *verbose >= 2 {
|
||||||
|
Config.LogLevel = LogLevelDebug
|
||||||
|
} else if *verbose >= 1 {
|
||||||
|
Config.LogLevel = LogLevelInfo
|
||||||
|
}
|
||||||
|
if *quiet {
|
||||||
|
if *verbose > 0 {
|
||||||
|
log.Fatalf("Can't set -v and -q")
|
||||||
|
}
|
||||||
|
Config.LogLevel = LogLevelError
|
||||||
|
}
|
||||||
|
logLevelFlag := pflag.Lookup("log-level")
|
||||||
|
if logLevelFlag != nil && logLevelFlag.Changed {
|
||||||
|
if *verbose > 0 {
|
||||||
|
log.Fatalf("Can't set -v and --log-level")
|
||||||
|
}
|
||||||
|
if *quiet {
|
||||||
|
log.Fatalf("Can't set -q and --log-level")
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(*logLevel) {
|
||||||
|
case "ERROR":
|
||||||
|
Config.LogLevel = LogLevelError
|
||||||
|
case "NOTICE":
|
||||||
|
Config.LogLevel = LogLevelNotice
|
||||||
|
case "INFO":
|
||||||
|
Config.LogLevel = LogLevelInfo
|
||||||
|
case "DEBUG":
|
||||||
|
Config.LogLevel = LogLevelDebug
|
||||||
|
default:
|
||||||
|
log.Fatalf("Unknown --log-level %q", *logLevel)
|
||||||
|
}
|
||||||
|
}
|
||||||
Config.ModifyWindow = *modifyWindow
|
Config.ModifyWindow = *modifyWindow
|
||||||
Config.Checkers = *checkers
|
Config.Checkers = *checkers
|
||||||
Config.Transfers = *transfers
|
Config.Transfers = *transfers
|
||||||
|
|
|
@ -313,3 +313,12 @@ func StringArrayP(name, shorthand string, value []string, usage string) (out *[]
|
||||||
setDefaultFromEnv(name)
|
setDefaultFromEnv(name)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountP defines a flag which can be overridden by an environment variable
|
||||||
|
//
|
||||||
|
// It is a thin wrapper around pflag.CountP
|
||||||
|
func CountP(name, shorthand string, usage string) (out *int) {
|
||||||
|
out = pflag.CountP(name, shorthand, usage)
|
||||||
|
setDefaultFromEnv(name)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
37
fs/log.go
37
fs/log.go
|
@ -11,9 +11,11 @@ import (
|
||||||
// LogLevel describes rclone's logs. These are a subset of the syslog log levels.
|
// LogLevel describes rclone's logs. These are a subset of the syslog log levels.
|
||||||
type LogLevel byte
|
type LogLevel byte
|
||||||
|
|
||||||
|
//go:generate stringer -type=LogLevel
|
||||||
|
|
||||||
// Log levels - a subset of the syslog logs
|
// Log levels - a subset of the syslog logs
|
||||||
const (
|
const (
|
||||||
LogLevelEmergency = iota
|
LogLevelEmergency LogLevel = iota
|
||||||
LogLevelAlert
|
LogLevelAlert
|
||||||
LogLevelCritical
|
LogLevelCritical
|
||||||
LogLevelError // Error - can't be suppressed
|
LogLevelError // Error - can't be suppressed
|
||||||
|
@ -38,30 +40,37 @@ func makeLog(o interface{}, text string, args ...interface{}) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf writes error log output for this Object or Fs. It
|
// Errorf writes error log output for this Object or Fs. It
|
||||||
// unconditionally logs a message regardless of Config.Quiet or
|
// unconditionally logs a message regardless of Config.LogLevel
|
||||||
// Config.Verbose.
|
|
||||||
func Errorf(o interface{}, text string, args ...interface{}) {
|
func Errorf(o interface{}, text string, args ...interface{}) {
|
||||||
log.Print(makeLog(o, text, args...))
|
if Config.LogLevel >= LogLevelError {
|
||||||
}
|
|
||||||
|
|
||||||
// Logf writes log output for this Object or Fs. This should be
|
|
||||||
// considered to be Info level logging.
|
|
||||||
func Logf(o interface{}, text string, args ...interface{}) {
|
|
||||||
if !Config.Quiet {
|
|
||||||
log.Print(makeLog(o, text, args...))
|
log.Print(makeLog(o, text, args...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infof writes info on transfers for this Object or Fs
|
// Logf writes log output for this Object or Fs. This should be
|
||||||
|
// considered to be Info level logging. It is the default level. By
|
||||||
|
// default rclone should not log very much so only use this for
|
||||||
|
// important things the user should see. The user can filter these
|
||||||
|
// out with the -q flag.
|
||||||
|
func Logf(o interface{}, text string, args ...interface{}) {
|
||||||
|
if Config.LogLevel >= LogLevelNotice {
|
||||||
|
log.Print(makeLog(o, text, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof writes info on transfers for this Object or Fs. Use this
|
||||||
|
// level for logging transfers, deletions and things which should
|
||||||
|
// appear with the -v flag.
|
||||||
func Infof(o interface{}, text string, args ...interface{}) {
|
func Infof(o interface{}, text string, args ...interface{}) {
|
||||||
if Config.Verbose {
|
if Config.LogLevel >= LogLevelInfo {
|
||||||
DebugLogger.Print(makeLog(o, text, args...))
|
DebugLogger.Print(makeLog(o, text, args...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugf writes debugging output for this Object or Fs
|
// Debugf writes debugging output for this Object or Fs. Use this for
|
||||||
|
// debug only. The user must have to specify -vv to see this.
|
||||||
func Debugf(o interface{}, text string, args ...interface{}) {
|
func Debugf(o interface{}, text string, args ...interface{}) {
|
||||||
if Config.Verbose {
|
if Config.LogLevel >= LogLevelDebug {
|
||||||
DebugLogger.Print(makeLog(o, text, args...))
|
DebugLogger.Print(makeLog(o, text, args...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
fs/loglevel_string.go
Normal file
16
fs/loglevel_string.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Code generated by "stringer -type=LogLevel"; DO NOT EDIT
|
||||||
|
|
||||||
|
package fs
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const _LogLevel_name = "LogLevelEmergencyLogLevelAlertLogLevelCriticalLogLevelErrorLogLevelWarningLogLevelNoticeLogLevelInfoLogLevelDebug"
|
||||||
|
|
||||||
|
var _LogLevel_index = [...]uint8{0, 17, 30, 46, 59, 74, 88, 100, 113}
|
||||||
|
|
||||||
|
func (i LogLevel) String() string {
|
||||||
|
if i >= LogLevel(len(_LogLevel_index)-1) {
|
||||||
|
return fmt.Sprintf("LogLevel(%d)", i)
|
||||||
|
}
|
||||||
|
return _LogLevel_name[_LogLevel_index[i]:_LogLevel_index[i+1]]
|
||||||
|
}
|
|
@ -105,8 +105,9 @@ func newRun() *Run {
|
||||||
// "RCLONE_CONFIG_PASS=hunter2" (or your password)
|
// "RCLONE_CONFIG_PASS=hunter2" (or your password)
|
||||||
*fs.AskPassword = false
|
*fs.AskPassword = false
|
||||||
fs.LoadConfig()
|
fs.LoadConfig()
|
||||||
fs.Config.Verbose = *Verbose
|
if *Verbose {
|
||||||
fs.Config.Quiet = !*Verbose
|
fs.Config.LogLevel = fs.LogLevelDebug
|
||||||
|
}
|
||||||
fs.Config.DumpHeaders = *DumpHeaders
|
fs.Config.DumpHeaders = *DumpHeaders
|
||||||
fs.Config.DumpBodies = *DumpBodies
|
fs.Config.DumpBodies = *DumpBodies
|
||||||
fs.Config.LowLevelRetries = *LowLevelRetries
|
fs.Config.LowLevelRetries = *LowLevelRetries
|
||||||
|
|
|
@ -73,8 +73,9 @@ func TestInit(t *testing.T) {
|
||||||
for _, item := range ExtraConfig {
|
for _, item := range ExtraConfig {
|
||||||
fs.ConfigFileSet(item.Name, item.Key, item.Value)
|
fs.ConfigFileSet(item.Name, item.Key, item.Value)
|
||||||
}
|
}
|
||||||
fs.Config.Verbose = *verbose
|
if *verbose {
|
||||||
fs.Config.Quiet = !*verbose
|
fs.Config.LogLevel = fs.LogLevelDebug
|
||||||
|
}
|
||||||
fs.Config.DumpHeaders = *dumpHeaders
|
fs.Config.DumpHeaders = *dumpHeaders
|
||||||
fs.Config.DumpBodies = *dumpBodies
|
fs.Config.DumpBodies = *dumpBodies
|
||||||
t.Logf("Using remote %q", RemoteName)
|
t.Logf("Using remote %q", RemoteName)
|
||||||
|
|
Loading…
Reference in a new issue