github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/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/ncw/rclone/fs" 13 "github.com/ncw/rclone/fs/config/flags" 14 ) 15 16 // Flags 17 var ( 18 logFile = flags.StringP("log-file", "", "", "Log everything to this file") 19 logFormat = flags.StringP("log-format", "", "date,time", "Comma separated list of log format options") 20 useSyslog = flags.BoolP("syslog", "", false, "Use Syslog for logging") 21 syslogFacility = flags.StringP("syslog-facility", "", "DAEMON", "Facility for syslog, eg KERN,USER,...") 22 ) 23 24 // fnName returns the name of the calling +2 function 25 func fnName() string { 26 pc, _, _, ok := runtime.Caller(2) 27 name := "*Unknown*" 28 if ok { 29 name = runtime.FuncForPC(pc).Name() 30 dot := strings.LastIndex(name, ".") 31 if dot >= 0 { 32 name = name[dot+1:] 33 } 34 } 35 return name 36 } 37 38 // Trace debugs the entry and exit of the calling function 39 // 40 // It is designed to be used in a defer statement so it returns a 41 // function that logs the exit parameters. 42 // 43 // Any pointers in the exit function will be dereferenced 44 func Trace(o interface{}, format string, a ...interface{}) func(string, ...interface{}) { 45 if fs.Config.LogLevel < fs.LogLevelDebug { 46 return func(format string, a ...interface{}) {} 47 } 48 name := fnName() 49 fs.LogPrintf(fs.LogLevelDebug, o, name+": "+format, a...) 50 return func(format string, a ...interface{}) { 51 for i := range a { 52 // read the values of the pointed to items 53 typ := reflect.TypeOf(a[i]) 54 if typ.Kind() == reflect.Ptr { 55 value := reflect.ValueOf(a[i]) 56 if value.IsNil() { 57 a[i] = nil 58 } else { 59 pointedToValue := reflect.Indirect(value) 60 a[i] = pointedToValue.Interface() 61 } 62 } 63 } 64 fs.LogPrintf(fs.LogLevelDebug, o, ">"+name+": "+format, a...) 65 } 66 } 67 68 // InitLogging start the logging as per the command line flags 69 func InitLogging() { 70 flagsStr := "," + *logFormat + "," 71 var flags int 72 if strings.Contains(flagsStr, ",date,") { 73 flags |= log.Ldate 74 } 75 if strings.Contains(flagsStr, ",time,") { 76 flags |= log.Ltime 77 } 78 if strings.Contains(flagsStr, ",microseconds,") { 79 flags |= log.Lmicroseconds 80 } 81 if strings.Contains(flagsStr, ",longfile,") { 82 flags |= log.Llongfile 83 } 84 if strings.Contains(flagsStr, ",shortfile,") { 85 flags |= log.Lshortfile 86 } 87 if strings.Contains(flagsStr, ",UTC,") { 88 flags |= log.LUTC 89 } 90 log.SetFlags(flags) 91 92 // Log file output 93 if *logFile != "" { 94 f, err := os.OpenFile(*logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640) 95 if err != nil { 96 log.Fatalf("Failed to open log file: %v", err) 97 } 98 _, err = f.Seek(0, io.SeekEnd) 99 if err != nil { 100 fs.Errorf(nil, "Failed to seek log file to end: %v", err) 101 } 102 log.SetOutput(f) 103 redirectStderr(f) 104 } 105 106 // Syslog output 107 if *useSyslog { 108 if *logFile != "" { 109 log.Fatalf("Can't use --syslog and --log-file together") 110 } 111 startSysLog() 112 } 113 } 114 115 // Redirected returns true if the log has been redirected from stdout 116 func Redirected() bool { 117 return *useSyslog || *logFile != "" 118 }