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:
Nick Craig-Wood 2017-02-09 21:22:46 +00:00
parent 0366ea39c5
commit ac1c041377
9 changed files with 137 additions and 40 deletions

View File

@ -274,12 +274,10 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
if err != nil {
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)
}
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() {
os.Exit(1)
}

View File

@ -71,8 +71,9 @@ func newRun() *Run {
// "RCLONE_CONFIG_PASS=hunter2" (or your password)
*fs.AskPassword = false
fs.LoadConfig()
fs.Config.Verbose = *Verbose
fs.Config.Quiet = !*Verbose
if *Verbose {
fs.Config.LogLevel = fs.LogLevelDebug
}
fs.Config.DumpHeaders = *DumpHeaders
fs.Config.DumpBodies = *DumpBodies
fs.Config.LowLevelRetries = *LowLevelRetries

View File

@ -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
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 ###
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
and faster than using `--checksum`.
### -v, --verbose ###
### -v, -vv, --verbose ###
If you set this flag, rclone will become very verbose telling you
about every file it considers and transfers.
With `-v` rclone will tell you about each file that is transferred and
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 ###
@ -762,22 +780,34 @@ See the [filtering section](/filtering/).
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`
to standard output. This means you can redirect standard output and
standard error to different places.
By default rclone logs to standard error. This means you can redirect
standard error and still see the normal output of rclone commands (eg
`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 `-v` flag, rclone will produce `Error`, `Info` and
`Debug` messages.
If you use the `-v` flag, rclone will produce `Error`, `Notice` and
`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`,
`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
---------

View File

@ -26,6 +26,7 @@ import (
"github.com/Unknwon/goconfig"
"github.com/pkg/errors"
"github.com/spf13/pflag"
"golang.org/x/crypto/nacl/secretbox"
"golang.org/x/text/unicode/norm"
)
@ -56,8 +57,9 @@ var (
// Config is the global config
Config = &ConfigInfo{}
// 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")
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")
checkers = IntP("checkers", "", 8, "Number of checkers 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
type ConfigInfo struct {
Verbose bool
Quiet bool
LogLevel LogLevel
DryRun bool
CheckSum bool
SizeOnly bool
@ -300,8 +301,39 @@ func LoadConfig() {
// Read some flags if set
//
// FIXME read these from the config file too
Config.Verbose = *verbose
Config.Quiet = *quiet
Config.LogLevel = LogLevelNotice
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.Checkers = *checkers
Config.Transfers = *transfers

View File

@ -313,3 +313,12 @@ func StringArrayP(name, shorthand string, value []string, usage string) (out *[]
setDefaultFromEnv(name)
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
}

View File

@ -11,9 +11,11 @@ import (
// LogLevel describes rclone's logs. These are a subset of the syslog log levels.
type LogLevel byte
//go:generate stringer -type=LogLevel
// Log levels - a subset of the syslog logs
const (
LogLevelEmergency = iota
LogLevelEmergency LogLevel = iota
LogLevelAlert
LogLevelCritical
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
// unconditionally logs a message regardless of Config.Quiet or
// Config.Verbose.
// unconditionally logs a message regardless of Config.LogLevel
func Errorf(o interface{}, text string, args ...interface{}) {
log.Print(makeLog(o, text, args...))
}
// 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 {
if Config.LogLevel >= LogLevelError {
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{}) {
if Config.Verbose {
if Config.LogLevel >= LogLevelInfo {
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{}) {
if Config.Verbose {
if Config.LogLevel >= LogLevelDebug {
DebugLogger.Print(makeLog(o, text, args...))
}
}

16
fs/loglevel_string.go Normal file
View 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]]
}

View File

@ -105,8 +105,9 @@ func newRun() *Run {
// "RCLONE_CONFIG_PASS=hunter2" (or your password)
*fs.AskPassword = false
fs.LoadConfig()
fs.Config.Verbose = *Verbose
fs.Config.Quiet = !*Verbose
if *Verbose {
fs.Config.LogLevel = fs.LogLevelDebug
}
fs.Config.DumpHeaders = *DumpHeaders
fs.Config.DumpBodies = *DumpBodies
fs.Config.LowLevelRetries = *LowLevelRetries

View File

@ -73,8 +73,9 @@ func TestInit(t *testing.T) {
for _, item := range ExtraConfig {
fs.ConfigFileSet(item.Name, item.Key, item.Value)
}
fs.Config.Verbose = *verbose
fs.Config.Quiet = !*verbose
if *verbose {
fs.Config.LogLevel = fs.LogLevelDebug
}
fs.Config.DumpHeaders = *dumpHeaders
fs.Config.DumpBodies = *dumpBodies
t.Logf("Using remote %q", RemoteName)