1
0
mirror of https://github.com/rclone/rclone.git synced 2026-01-06 10:33:34 +00:00

Break the fs package up into smaller parts.

The purpose of this is to make it easier to maintain and eventually to
allow the rclone backends to be re-used in other projects without
having to use the rclone configuration system.

The new code layout is documented in CONTRIBUTING.
This commit is contained in:
Nick Craig-Wood
2018-01-12 16:30:54 +00:00
parent 92624bbbf1
commit 11da2a6c9b
183 changed files with 5749 additions and 5063 deletions

89
fs/log/log.go Normal file
View File

@@ -0,0 +1,89 @@
// Package log provides logging for rclone
package log
import (
"log"
"os"
"reflect"
"runtime"
"strings"
"github.com/ncw/rclone/fs"
"github.com/ncw/rclone/fs/config/flags"
)
// Flags
var (
logFile = flags.StringP("log-file", "", "", "Log everything to this file")
useSyslog = flags.BoolP("syslog", "", false, "Use Syslog for logging")
syslogFacility = flags.StringP("syslog-facility", "", "DAEMON", "Facility for syslog, eg KERN,USER,...")
)
// fnName returns the name of the calling +2 function
func fnName() string {
pc, _, _, ok := runtime.Caller(2)
name := "*Unknown*"
if ok {
name = runtime.FuncForPC(pc).Name()
dot := strings.LastIndex(name, ".")
if dot >= 0 {
name = name[dot+1:]
}
}
return name
}
// Trace debugs the entry and exit of the calling function
//
// It is designed to be used in a defer statement so it returns a
// function that logs the exit parameters.
//
// Any pointers in the exit function will be dereferenced
func Trace(o interface{}, format string, a ...interface{}) func(string, ...interface{}) {
if fs.Config.LogLevel < fs.LogLevelDebug {
return func(format string, a ...interface{}) {}
}
name := fnName()
fs.LogPrintf(fs.LogLevelDebug, o, name+": "+format, a...)
return func(format string, a ...interface{}) {
for i := range a {
// read the values of the pointed to items
typ := reflect.TypeOf(a[i])
if typ.Kind() == reflect.Ptr {
value := reflect.ValueOf(a[i])
if value.IsNil() {
a[i] = nil
} else {
pointedToValue := reflect.Indirect(value)
a[i] = pointedToValue.Interface()
}
}
}
fs.LogPrintf(fs.LogLevelDebug, o, ">"+name+": "+format, a...)
}
}
// InitLogging start the logging as per the command line flags
func InitLogging() {
// Log file output
if *logFile != "" {
f, err := os.OpenFile(*logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640)
if err != nil {
log.Fatalf("Failed to open log file: %v", err)
}
_, err = f.Seek(0, os.SEEK_END)
if err != nil {
fs.Errorf(nil, "Failed to seek log file to end: %v", err)
}
log.SetOutput(f)
redirectStderr(f)
}
// Syslog output
if *useSyslog {
if *logFile != "" {
log.Fatalf("Can't use --syslog and --log-file together")
}
startSysLog()
}
}

16
fs/log/redirect_stderr.go Normal file
View File

@@ -0,0 +1,16 @@
// Log the panic to the log file - for oses which can't do this
// +build !windows,!darwin,!dragonfly,!freebsd,!linux,!nacl,!netbsd,!openbsd
package log
import (
"os"
"github.com/ncw/rclone/fs"
)
// redirectStderr to the file passed in
func redirectStderr(f *os.File) {
fs.Errorf(nil, "Can't redirect stderr to file")
}

View File

@@ -0,0 +1,20 @@
// Log the panic under unix to the log file
// +build !windows,!solaris,!plan9
package log
import (
"log"
"os"
"golang.org/x/sys/unix"
)
// redirectStderr to the file passed in
func redirectStderr(f *os.File) {
err := unix.Dup2(int(f.Fd()), int(os.Stderr.Fd()))
if err != nil {
log.Fatalf("Failed to redirect stderr to file: %v", err)
}
}

View File

@@ -0,0 +1,39 @@
// Log the panic under windows to the log file
//
// Code from minix, via
//
// https://play.golang.org/p/kLtct7lSUg
// +build windows
package log
import (
"log"
"os"
"syscall"
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
procSetStdHandle = kernel32.MustFindProc("SetStdHandle")
)
func setStdHandle(stdhandle int32, handle syscall.Handle) error {
r0, _, e1 := syscall.Syscall(procSetStdHandle.Addr(), 2, uintptr(stdhandle), uintptr(handle), 0)
if r0 == 0 {
if e1 != 0 {
return error(e1)
}
return syscall.EINVAL
}
return nil
}
// redirectStderr to the file passed in
func redirectStderr(f *os.File) {
err := setStdHandle(syscall.STD_ERROR_HANDLE, syscall.Handle(f.Fd()))
if err != nil {
log.Fatalf("Failed to redirect stderr to file: %v", err)
}
}

16
fs/log/syslog.go Normal file
View File

@@ -0,0 +1,16 @@
// Syslog interface for non-Unix variants only
// +build windows nacl plan9
package log
import (
"log"
"runtime"
)
// Starts syslog if configured, returns true if it was started
func startSysLog() bool {
log.Fatalf("--syslog not supported on %s platform", runtime.GOOS)
return false
}

67
fs/log/syslog_unix.go Normal file
View File

@@ -0,0 +1,67 @@
// Syslog interface for Unix variants only
// +build !windows,!nacl,!plan9
package log
import (
"log"
"log/syslog"
"os"
"path"
"github.com/ncw/rclone/fs"
)
var (
syslogFacilityMap = map[string]syslog.Priority{
"KERN": syslog.LOG_KERN,
"USER": syslog.LOG_USER,
"MAIL": syslog.LOG_MAIL,
"DAEMON": syslog.LOG_DAEMON,
"AUTH": syslog.LOG_AUTH,
"SYSLOG": syslog.LOG_SYSLOG,
"LPR": syslog.LOG_LPR,
"NEWS": syslog.LOG_NEWS,
"UUCP": syslog.LOG_UUCP,
"CRON": syslog.LOG_CRON,
"AUTHPRIV": syslog.LOG_AUTHPRIV,
"FTP": syslog.LOG_FTP,
}
)
// Starts syslog
func startSysLog() bool {
facility, ok := syslogFacilityMap[*syslogFacility]
if !ok {
log.Fatalf("Unknown syslog facility %q - man syslog for list", *syslogFacility)
}
Me := path.Base(os.Args[0])
w, err := syslog.New(syslog.LOG_NOTICE|facility, Me)
if err != nil {
log.Fatalf("Failed to start syslog: %v", err)
}
log.SetFlags(0)
log.SetOutput(w)
fs.LogPrint = func(level fs.LogLevel, text string) {
switch level {
case fs.LogLevelEmergency:
_ = w.Emerg(text)
case fs.LogLevelAlert:
_ = w.Alert(text)
case fs.LogLevelCritical:
_ = w.Crit(text)
case fs.LogLevelError:
_ = w.Err(text)
case fs.LogLevelWarning:
_ = w.Warning(text)
case fs.LogLevelNotice:
_ = w.Notice(text)
case fs.LogLevelInfo:
_ = w.Info(text)
case fs.LogLevelDebug:
_ = w.Debug(text)
}
}
return true
}