github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/log/log.go (about) 1 // Package log provides logging for rclone 2 package log 3 4 import ( 5 "io" 6 "log" 7 "os" 8 "reflect" 9 "runtime" 10 "strings" 11 12 "github.com/rclone/rclone/fs" 13 ) 14 15 // Options contains options for the remote control server 16 type Options struct { 17 File string // Log everything to this file 18 Format string // Comma separated list of log format options 19 UseSyslog bool // Use Syslog for logging 20 SyslogFacility string // Facility for syslog, eg KERN,USER,... 21 } 22 23 // DefaultOpt is the default values used for Opt 24 var DefaultOpt = Options{ 25 Format: "date,time", 26 SyslogFacility: "DAEMON", 27 } 28 29 // Opt is the options for the logger 30 var Opt = DefaultOpt 31 32 // fnName returns the name of the calling +2 function 33 func fnName() string { 34 pc, _, _, ok := runtime.Caller(2) 35 name := "*Unknown*" 36 if ok { 37 name = runtime.FuncForPC(pc).Name() 38 dot := strings.LastIndex(name, ".") 39 if dot >= 0 { 40 name = name[dot+1:] 41 } 42 } 43 return name 44 } 45 46 // Trace debugs the entry and exit of the calling function 47 // 48 // It is designed to be used in a defer statement so it returns a 49 // function that logs the exit parameters. 50 // 51 // Any pointers in the exit function will be dereferenced 52 func Trace(o interface{}, format string, a ...interface{}) func(string, ...interface{}) { 53 if fs.Config.LogLevel < fs.LogLevelDebug { 54 return func(format string, a ...interface{}) {} 55 } 56 name := fnName() 57 fs.LogPrintf(fs.LogLevelDebug, o, name+": "+format, a...) 58 return func(format string, a ...interface{}) { 59 for i := range a { 60 // read the values of the pointed to items 61 typ := reflect.TypeOf(a[i]) 62 if typ.Kind() == reflect.Ptr { 63 value := reflect.ValueOf(a[i]) 64 if value.IsNil() { 65 a[i] = nil 66 } else { 67 pointedToValue := reflect.Indirect(value) 68 a[i] = pointedToValue.Interface() 69 } 70 } 71 } 72 fs.LogPrintf(fs.LogLevelDebug, o, ">"+name+": "+format, a...) 73 } 74 } 75 76 // Stack logs a stack trace of callers with the o and info passed in 77 func Stack(o interface{}, info string) { 78 if fs.Config.LogLevel < fs.LogLevelDebug { 79 return 80 } 81 arr := [16 * 1024]byte{} 82 buf := arr[:] 83 n := runtime.Stack(buf, false) 84 buf = buf[:n] 85 fs.LogPrintf(fs.LogLevelDebug, o, "%s\nStack trace:\n%s", info, buf) 86 } 87 88 // InitLogging start the logging as per the command line flags 89 func InitLogging() { 90 flagsStr := "," + Opt.Format + "," 91 var flags int 92 if strings.Contains(flagsStr, ",date,") { 93 flags |= log.Ldate 94 } 95 if strings.Contains(flagsStr, ",time,") { 96 flags |= log.Ltime 97 } 98 if strings.Contains(flagsStr, ",microseconds,") { 99 flags |= log.Lmicroseconds 100 } 101 if strings.Contains(flagsStr, ",longfile,") { 102 flags |= log.Llongfile 103 } 104 if strings.Contains(flagsStr, ",shortfile,") { 105 flags |= log.Lshortfile 106 } 107 if strings.Contains(flagsStr, ",UTC,") { 108 flags |= log.LUTC 109 } 110 log.SetFlags(flags) 111 112 // Log file output 113 if Opt.File != "" { 114 f, err := os.OpenFile(Opt.File, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640) 115 if err != nil { 116 log.Fatalf("Failed to open log file: %v", err) 117 } 118 _, err = f.Seek(0, io.SeekEnd) 119 if err != nil { 120 fs.Errorf(nil, "Failed to seek log file to end: %v", err) 121 } 122 log.SetOutput(f) 123 redirectStderr(f) 124 } 125 126 // Syslog output 127 if Opt.UseSyslog { 128 if Opt.File != "" { 129 log.Fatalf("Can't use --syslog and --log-file together") 130 } 131 startSysLog() 132 } 133 } 134 135 // Redirected returns true if the log has been redirected from stdout 136 func Redirected() bool { 137 return Opt.UseSyslog || Opt.File != "" 138 }