2017-02-09 11:01:20 +00:00
|
|
|
package fs
|
|
|
|
|
|
|
|
import (
|
2020-11-05 11:33:32 +00:00
|
|
|
"context"
|
2017-02-09 11:01:20 +00:00
|
|
|
"fmt"
|
|
|
|
"log"
|
2017-06-26 21:46:45 +00:00
|
|
|
|
2020-09-18 15:37:54 +00:00
|
|
|
sysdjournald "github.com/iguanesolutions/go-systemd/v5/journald"
|
2017-06-26 21:46:45 +00:00
|
|
|
"github.com/pkg/errors"
|
2019-07-26 00:54:09 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2017-02-09 11:01:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// LogLevel describes rclone's logs. These are a subset of the syslog log levels.
|
|
|
|
type LogLevel byte
|
|
|
|
|
2017-02-10 13:28:06 +00:00
|
|
|
// Log levels. These are the syslog levels of which we only use a
|
|
|
|
// subset.
|
|
|
|
//
|
|
|
|
// LOG_EMERG system is unusable
|
|
|
|
// LOG_ALERT action must be taken immediately
|
|
|
|
// LOG_CRIT critical conditions
|
|
|
|
// LOG_ERR error conditions
|
|
|
|
// LOG_WARNING warning conditions
|
|
|
|
// LOG_NOTICE normal, but significant, condition
|
|
|
|
// LOG_INFO informational message
|
|
|
|
// LOG_DEBUG debug-level message
|
2017-02-09 11:01:20 +00:00
|
|
|
const (
|
2017-02-09 21:22:46 +00:00
|
|
|
LogLevelEmergency LogLevel = iota
|
2017-02-09 11:01:20 +00:00
|
|
|
LogLevelAlert
|
|
|
|
LogLevelCritical
|
|
|
|
LogLevelError // Error - can't be suppressed
|
|
|
|
LogLevelWarning
|
|
|
|
LogLevelNotice // Normal logging, -q suppresses
|
|
|
|
LogLevelInfo // Transfers, needs -v
|
|
|
|
LogLevelDebug // Debug level, needs -vv
|
|
|
|
)
|
|
|
|
|
2017-02-10 13:28:06 +00:00
|
|
|
var logLevelToString = []string{
|
|
|
|
LogLevelEmergency: "EMERGENCY",
|
|
|
|
LogLevelAlert: "ALERT",
|
|
|
|
LogLevelCritical: "CRITICAL",
|
|
|
|
LogLevelError: "ERROR",
|
|
|
|
LogLevelWarning: "WARNING",
|
|
|
|
LogLevelNotice: "NOTICE",
|
|
|
|
LogLevelInfo: "INFO",
|
|
|
|
LogLevelDebug: "DEBUG",
|
|
|
|
}
|
2017-02-09 11:01:20 +00:00
|
|
|
|
2017-02-10 13:28:06 +00:00
|
|
|
// String turns a LogLevel into a string
|
|
|
|
func (l LogLevel) String() string {
|
|
|
|
if l >= LogLevel(len(logLevelToString)) {
|
|
|
|
return fmt.Sprintf("LogLevel(%d)", l)
|
|
|
|
}
|
|
|
|
return logLevelToString[l]
|
|
|
|
}
|
2017-02-09 11:01:20 +00:00
|
|
|
|
2017-06-26 21:46:45 +00:00
|
|
|
// Set a LogLevel
|
|
|
|
func (l *LogLevel) Set(s string) error {
|
|
|
|
for n, name := range logLevelToString {
|
|
|
|
if s != "" && name == s {
|
|
|
|
*l = LogLevel(n)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return errors.Errorf("Unknown log level %q", s)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Type of the value
|
|
|
|
func (l *LogLevel) Type() string {
|
|
|
|
return "string"
|
|
|
|
}
|
|
|
|
|
2018-01-12 16:30:54 +00:00
|
|
|
// LogPrint sends the text to the logger of level
|
|
|
|
var LogPrint = func(level LogLevel, text string) {
|
2020-09-18 15:37:54 +00:00
|
|
|
var prefix string
|
2020-11-05 11:33:32 +00:00
|
|
|
if GetConfig(context.TODO()).LogSystemdSupport {
|
2020-09-18 15:37:54 +00:00
|
|
|
switch level {
|
|
|
|
case LogLevelDebug:
|
|
|
|
prefix = sysdjournald.DebugPrefix
|
|
|
|
case LogLevelInfo:
|
|
|
|
prefix = sysdjournald.InfoPrefix
|
|
|
|
case LogLevelNotice:
|
|
|
|
prefix = sysdjournald.NoticePrefix
|
|
|
|
case LogLevelWarning:
|
|
|
|
prefix = sysdjournald.WarningPrefix
|
|
|
|
case LogLevelError:
|
|
|
|
prefix = sysdjournald.ErrPrefix
|
|
|
|
case LogLevelCritical:
|
|
|
|
prefix = sysdjournald.CritPrefix
|
|
|
|
case LogLevelAlert:
|
|
|
|
prefix = sysdjournald.AlertPrefix
|
|
|
|
case LogLevelEmergency:
|
|
|
|
prefix = sysdjournald.EmergPrefix
|
|
|
|
}
|
|
|
|
}
|
|
|
|
text = fmt.Sprintf("%s%-6s: %s", prefix, level, text)
|
2018-09-02 17:11:09 +00:00
|
|
|
_ = log.Output(4, text)
|
2017-02-10 13:28:06 +00:00
|
|
|
}
|
|
|
|
|
2020-04-11 17:02:50 +00:00
|
|
|
// LogValueItem describes keyed item for a JSON log entry
|
|
|
|
type LogValueItem struct {
|
|
|
|
key string
|
|
|
|
value interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// LogValue should be used as an argument to any logging calls to
|
|
|
|
// augment the JSON output with more structured information.
|
|
|
|
//
|
|
|
|
// key is the dictionary parameter used to store value.
|
|
|
|
func LogValue(key string, value interface{}) LogValueItem {
|
|
|
|
return LogValueItem{key: key, value: value}
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns an empty string so LogValueItem entries won't show
|
|
|
|
// in the textual representation of logs. They need to be put in so
|
|
|
|
// the number of parameters of the log call matches.
|
|
|
|
func (j LogValueItem) String() string {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2018-01-12 16:30:54 +00:00
|
|
|
// LogPrintf produces a log string from the arguments passed in
|
|
|
|
func LogPrintf(level LogLevel, o interface{}, text string, args ...interface{}) {
|
2017-02-09 11:01:20 +00:00
|
|
|
out := fmt.Sprintf(text, args...)
|
2019-08-02 14:57:09 +00:00
|
|
|
|
2020-11-05 11:33:32 +00:00
|
|
|
if GetConfig(context.TODO()).UseJSONLog {
|
2019-08-02 14:57:09 +00:00
|
|
|
fields := logrus.Fields{}
|
|
|
|
if o != nil {
|
|
|
|
fields = logrus.Fields{
|
|
|
|
"object": fmt.Sprintf("%+v", o),
|
|
|
|
"objectType": fmt.Sprintf("%T", o),
|
|
|
|
}
|
|
|
|
}
|
2020-04-11 17:02:50 +00:00
|
|
|
for _, arg := range args {
|
|
|
|
if item, ok := arg.(LogValueItem); ok {
|
|
|
|
fields[item.key] = item.value
|
|
|
|
}
|
2020-02-15 21:21:01 +00:00
|
|
|
}
|
2019-07-26 00:54:09 +00:00
|
|
|
switch level {
|
|
|
|
case LogLevelDebug:
|
2019-08-02 14:57:09 +00:00
|
|
|
logrus.WithFields(fields).Debug(out)
|
2019-07-26 00:54:09 +00:00
|
|
|
case LogLevelInfo:
|
2019-08-02 14:57:09 +00:00
|
|
|
logrus.WithFields(fields).Info(out)
|
2019-07-26 00:54:09 +00:00
|
|
|
case LogLevelNotice, LogLevelWarning:
|
2019-08-02 14:57:09 +00:00
|
|
|
logrus.WithFields(fields).Warn(out)
|
2019-07-26 00:54:09 +00:00
|
|
|
case LogLevelError:
|
2019-08-02 14:57:09 +00:00
|
|
|
logrus.WithFields(fields).Error(out)
|
2019-07-26 00:54:09 +00:00
|
|
|
case LogLevelCritical:
|
2019-08-02 14:57:09 +00:00
|
|
|
logrus.WithFields(fields).Fatal(out)
|
2019-07-26 00:54:09 +00:00
|
|
|
case LogLevelEmergency, LogLevelAlert:
|
2019-08-02 14:57:09 +00:00
|
|
|
logrus.WithFields(fields).Panic(out)
|
2019-07-26 00:54:09 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-08-02 14:57:09 +00:00
|
|
|
if o != nil {
|
|
|
|
out = fmt.Sprintf("%v: %s", o, out)
|
|
|
|
}
|
2019-07-26 00:54:09 +00:00
|
|
|
LogPrint(level, out)
|
|
|
|
}
|
2017-02-09 11:01:20 +00:00
|
|
|
}
|
|
|
|
|
2017-06-26 21:46:45 +00:00
|
|
|
// LogLevelPrintf writes logs at the given level
|
|
|
|
func LogLevelPrintf(level LogLevel, o interface{}, text string, args ...interface{}) {
|
2020-11-05 11:33:32 +00:00
|
|
|
if GetConfig(context.TODO()).LogLevel >= level {
|
2018-01-12 16:30:54 +00:00
|
|
|
LogPrintf(level, o, text, args...)
|
2017-06-26 21:46:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-09 11:01:20 +00:00
|
|
|
// Errorf writes error log output for this Object or Fs. It
|
2017-02-10 13:28:06 +00:00
|
|
|
// should always be seen by the user.
|
2017-02-09 11:01:20 +00:00
|
|
|
func Errorf(o interface{}, text string, args ...interface{}) {
|
2020-11-05 11:33:32 +00:00
|
|
|
if GetConfig(context.TODO()).LogLevel >= LogLevelError {
|
2018-01-12 16:30:54 +00:00
|
|
|
LogPrintf(LogLevelError, o, text, args...)
|
2017-02-09 21:22:46 +00:00
|
|
|
}
|
2017-02-09 11:01:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Logf writes log output for this Object or Fs. This should be
|
2017-02-09 21:22:46 +00:00
|
|
|
// 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.
|
2017-02-09 11:01:20 +00:00
|
|
|
func Logf(o interface{}, text string, args ...interface{}) {
|
2020-11-05 11:33:32 +00:00
|
|
|
if GetConfig(context.TODO()).LogLevel >= LogLevelNotice {
|
2018-01-12 16:30:54 +00:00
|
|
|
LogPrintf(LogLevelNotice, o, text, args...)
|
2017-02-09 11:01:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-09 21:22:46 +00:00
|
|
|
// 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.
|
2017-02-09 11:01:20 +00:00
|
|
|
func Infof(o interface{}, text string, args ...interface{}) {
|
2020-11-05 11:33:32 +00:00
|
|
|
if GetConfig(context.TODO()).LogLevel >= LogLevelInfo {
|
2018-01-12 16:30:54 +00:00
|
|
|
LogPrintf(LogLevelInfo, o, text, args...)
|
2017-02-09 11:01:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-09 21:22:46 +00:00
|
|
|
// Debugf writes debugging output for this Object or Fs. Use this for
|
|
|
|
// debug only. The user must have to specify -vv to see this.
|
2017-02-09 11:01:20 +00:00
|
|
|
func Debugf(o interface{}, text string, args ...interface{}) {
|
2020-11-05 11:33:32 +00:00
|
|
|
if GetConfig(context.TODO()).LogLevel >= LogLevelDebug {
|
2018-01-12 16:30:54 +00:00
|
|
|
LogPrintf(LogLevelDebug, o, text, args...)
|
2017-05-09 10:38:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-12 16:30:54 +00:00
|
|
|
// LogDirName returns an object for the logger, logging a root
|
|
|
|
// directory which would normally be "" as the Fs
|
|
|
|
func LogDirName(f Fs, dir string) interface{} {
|
|
|
|
if dir != "" {
|
|
|
|
return dir
|
2017-02-09 11:01:20 +00:00
|
|
|
}
|
2018-01-12 16:30:54 +00:00
|
|
|
return f
|
2017-02-09 11:01:20 +00:00
|
|
|
}
|