mirror of
https://github.com/rclone/rclone.git
synced 2026-01-07 02:54:04 +00:00
accounting: fix global error acounting
fs.CountError is called when an error is encountered. The method was calling GlobalStats().Error(err) which incremented the error at the global stats level. This led to calls to core/stats with group= filter returning an error count of 0 even if errors actually occured. This change requires the context to be provided when calling fs.CountError. Doing so, we can retrieve the correct StatsInfo to increment the errors from. Fixes #5865
This commit is contained in:
committed by
Nick Craig-Wood
parent
c053429b9c
commit
8a6fc8535d
46
cmd/cmd.go
46
cmd/cmd.go
@@ -83,12 +83,13 @@ func ShowVersion() {
|
||||
// It returns a string with the file name if points to a file
|
||||
// otherwise "".
|
||||
func NewFsFile(remote string) (fs.Fs, string) {
|
||||
ctx := context.Background()
|
||||
_, fsPath, err := fspath.SplitFs(remote)
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatalf(nil, "Failed to create file system for %q: %v", remote, err)
|
||||
}
|
||||
f, err := cache.Get(context.Background(), remote)
|
||||
f, err := cache.Get(ctx, remote)
|
||||
switch err {
|
||||
case fs.ErrorIsFile:
|
||||
cache.Pin(f) // pin indefinitely since it was on the CLI
|
||||
@@ -97,7 +98,7 @@ func NewFsFile(remote string) (fs.Fs, string) {
|
||||
cache.Pin(f) // pin indefinitely since it was on the CLI
|
||||
return f, ""
|
||||
default:
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatalf(nil, "Failed to create file system for %q: %v", remote, err)
|
||||
}
|
||||
return nil, ""
|
||||
@@ -108,18 +109,19 @@ func NewFsFile(remote string) (fs.Fs, string) {
|
||||
// This works the same as NewFsFile however it adds filters to the Fs
|
||||
// to limit it to a single file if the remote pointed to a file.
|
||||
func newFsFileAddFilter(remote string) (fs.Fs, string) {
|
||||
fi := filter.GetConfig(context.Background())
|
||||
ctx := context.Background()
|
||||
fi := filter.GetConfig(ctx)
|
||||
f, fileName := NewFsFile(remote)
|
||||
if fileName != "" {
|
||||
if !fi.InActive() {
|
||||
err := fmt.Errorf("can't limit to single files when using filters: %v", remote)
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatal(nil, err.Error())
|
||||
}
|
||||
// Limit transfers to this file
|
||||
err := fi.AddFile(fileName)
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatalf(nil, "Failed to limit to single file %q: %v", remote, err)
|
||||
}
|
||||
}
|
||||
@@ -139,9 +141,10 @@ func NewFsSrc(args []string) fs.Fs {
|
||||
//
|
||||
// This must point to a directory
|
||||
func newFsDir(remote string) fs.Fs {
|
||||
f, err := cache.Get(context.Background(), remote)
|
||||
ctx := context.Background()
|
||||
f, err := cache.Get(ctx, remote)
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatalf(nil, "Failed to create file system for %q: %v", remote, err)
|
||||
}
|
||||
cache.Pin(f) // pin indefinitely since it was on the CLI
|
||||
@@ -175,6 +178,7 @@ func NewFsSrcFileDst(args []string) (fsrc fs.Fs, srcFileName string, fdst fs.Fs)
|
||||
// NewFsSrcDstFiles creates a new src and dst fs from the arguments
|
||||
// If src is a file then srcFileName and dstFileName will be non-empty
|
||||
func NewFsSrcDstFiles(args []string) (fsrc fs.Fs, srcFileName string, fdst fs.Fs, dstFileName string) {
|
||||
ctx := context.Background()
|
||||
fsrc, srcFileName = newFsFileAddFilter(args[0])
|
||||
// If copying a file...
|
||||
dstRemote := args[1]
|
||||
@@ -193,14 +197,14 @@ func NewFsSrcDstFiles(args []string) (fsrc fs.Fs, srcFileName string, fdst fs.Fs
|
||||
fs.Fatalf(nil, "%q is a directory", args[1])
|
||||
}
|
||||
}
|
||||
fdst, err := cache.Get(context.Background(), dstRemote)
|
||||
fdst, err := cache.Get(ctx, dstRemote)
|
||||
switch err {
|
||||
case fs.ErrorIsFile:
|
||||
_ = fs.CountError(err)
|
||||
_ = fs.CountError(ctx, err)
|
||||
fs.Fatalf(nil, "Source doesn't exist or is a directory and destination is a file")
|
||||
case nil:
|
||||
default:
|
||||
_ = fs.CountError(err)
|
||||
_ = fs.CountError(ctx, err)
|
||||
fs.Fatalf(nil, "Failed to create file system for destination %q: %v", dstRemote, err)
|
||||
}
|
||||
cache.Pin(fdst) // pin indefinitely since it was on the CLI
|
||||
@@ -234,7 +238,8 @@ func ShowStats() bool {
|
||||
|
||||
// Run the function with stats and retries if required
|
||||
func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
|
||||
ci := fs.GetConfig(context.Background())
|
||||
ctx := context.Background()
|
||||
ci := fs.GetConfig(ctx)
|
||||
var cmdErr error
|
||||
stopStats := func() {}
|
||||
if !showStats && ShowStats() {
|
||||
@@ -248,7 +253,7 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
|
||||
SigInfoHandler()
|
||||
for try := 1; try <= ci.Retries; try++ {
|
||||
cmdErr = f()
|
||||
cmdErr = fs.CountError(cmdErr)
|
||||
cmdErr = fs.CountError(ctx, cmdErr)
|
||||
lastErr := accounting.GlobalStats().GetLastError()
|
||||
if cmdErr == nil {
|
||||
cmdErr = lastErr
|
||||
@@ -436,19 +441,19 @@ func initConfig() {
|
||||
fs.Infof(nil, "Creating CPU profile %q\n", *cpuProfile)
|
||||
f, err := os.Create(*cpuProfile)
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatal(nil, fmt.Sprint(err))
|
||||
}
|
||||
err = pprof.StartCPUProfile(f)
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatal(nil, fmt.Sprint(err))
|
||||
}
|
||||
atexit.Register(func() {
|
||||
pprof.StopCPUProfile()
|
||||
err := f.Close()
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatal(nil, fmt.Sprint(err))
|
||||
}
|
||||
})
|
||||
@@ -460,17 +465,17 @@ func initConfig() {
|
||||
fs.Infof(nil, "Saving Memory profile %q\n", *memProfile)
|
||||
f, err := os.Create(*memProfile)
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatal(nil, fmt.Sprint(err))
|
||||
}
|
||||
err = pprof.WriteHeapProfile(f)
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatal(nil, fmt.Sprint(err))
|
||||
}
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Fatal(nil, fmt.Sprint(err))
|
||||
}
|
||||
})
|
||||
@@ -478,7 +483,8 @@ func initConfig() {
|
||||
}
|
||||
|
||||
func resolveExitCode(err error) {
|
||||
ci := fs.GetConfig(context.Background())
|
||||
ctx := context.Background()
|
||||
ci := fs.GetConfig(ctx)
|
||||
atexit.Run()
|
||||
if err == nil {
|
||||
if ci.ErrorOnNoTransfer {
|
||||
|
||||
@@ -190,16 +190,17 @@ func (s *server) ModelNumber() string {
|
||||
|
||||
// Renders the root device descriptor.
|
||||
func (s *server) rootDescHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
tmpl, err := data.GetTemplate()
|
||||
if err != nil {
|
||||
serveError(s, w, "Failed to load root descriptor template", err)
|
||||
serveError(ctx, s, w, "Failed to load root descriptor template", err)
|
||||
return
|
||||
}
|
||||
|
||||
buffer := new(bytes.Buffer)
|
||||
err = tmpl.Execute(buffer, s)
|
||||
if err != nil {
|
||||
serveError(s, w, "Failed to render root descriptor XML", err)
|
||||
serveError(ctx, s, w, "Failed to render root descriptor XML", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -215,15 +216,16 @@ func (s *server) rootDescHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Handle a service control HTTP request.
|
||||
func (s *server) serviceControlHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
soapActionString := r.Header.Get("SOAPACTION")
|
||||
soapAction, err := upnp.ParseActionHTTPHeader(soapActionString)
|
||||
if err != nil {
|
||||
serveError(s, w, "Could not parse SOAPACTION header", err)
|
||||
serveError(ctx, s, w, "Could not parse SOAPACTION header", err)
|
||||
return
|
||||
}
|
||||
var env soap.Envelope
|
||||
if err := xml.NewDecoder(r.Body).Decode(&env); err != nil {
|
||||
serveError(s, w, "Could not parse SOAP request body", err)
|
||||
serveError(ctx, s, w, "Could not parse SOAP request body", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -257,6 +259,7 @@ func (s *server) soapActionResponse(sa upnp.SoapAction, actionRequestXML []byte,
|
||||
|
||||
// Serves actual resources (media files).
|
||||
func (s *server) resourceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
remotePath := r.URL.Path
|
||||
node, err := s.vfs.Stat(r.URL.Path)
|
||||
if err != nil {
|
||||
@@ -277,7 +280,7 @@ func (s *server) resourceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
file := node.(*vfs.File)
|
||||
in, err := file.Open(os.O_RDONLY)
|
||||
if err != nil {
|
||||
serveError(node, w, "Could not open resource", err)
|
||||
serveError(ctx, node, w, "Could not open resource", err)
|
||||
return
|
||||
}
|
||||
defer fs.CheckClose(in, &err)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dlna
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
@@ -142,9 +143,10 @@ func logging(next http.Handler) http.Handler {
|
||||
// Error recovery and general request logging are left to logging().
|
||||
func traceLogging(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
dump, err := httputil.DumpRequest(r, true)
|
||||
if err != nil {
|
||||
serveError(nil, w, "error dumping request", err)
|
||||
serveError(ctx, nil, w, "error dumping request", err)
|
||||
return
|
||||
}
|
||||
fs.Debugf(nil, "%s", dump)
|
||||
@@ -182,8 +184,8 @@ func withHeader(name string, value string, next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
// serveError returns an http.StatusInternalServerError and logs the error
|
||||
func serveError(what interface{}, w http.ResponseWriter, text string, err error) {
|
||||
err = fs.CountError(err)
|
||||
func serveError(ctx context.Context, what interface{}, w http.ResponseWriter, text string, err error) {
|
||||
err = fs.CountError(ctx, err)
|
||||
fs.Errorf(what, "%s: %v", text, err)
|
||||
http.Error(w, text+".", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
@@ -186,6 +186,7 @@ func (s *HTTP) handler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// serveDir serves a directory index at dirRemote
|
||||
func (s *HTTP) serveDir(w http.ResponseWriter, r *http.Request, dirRemote string) {
|
||||
ctx := r.Context()
|
||||
VFS, err := s.getVFS(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, "Root directory not found", http.StatusNotFound)
|
||||
@@ -198,7 +199,7 @@ func (s *HTTP) serveDir(w http.ResponseWriter, r *http.Request, dirRemote string
|
||||
http.Error(w, "Directory not found", http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
serve.Error(dirRemote, w, "Failed to list directory", err)
|
||||
serve.Error(ctx, dirRemote, w, "Failed to list directory", err)
|
||||
return
|
||||
}
|
||||
if !node.IsDir() {
|
||||
@@ -208,7 +209,7 @@ func (s *HTTP) serveDir(w http.ResponseWriter, r *http.Request, dirRemote string
|
||||
dir := node.(*vfs.Dir)
|
||||
dirEntries, err := dir.ReadDirAll()
|
||||
if err != nil {
|
||||
serve.Error(dirRemote, w, "Failed to list directory", err)
|
||||
serve.Error(ctx, dirRemote, w, "Failed to list directory", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -234,6 +235,7 @@ func (s *HTTP) serveDir(w http.ResponseWriter, r *http.Request, dirRemote string
|
||||
|
||||
// serveFile serves a file object at remote
|
||||
func (s *HTTP) serveFile(w http.ResponseWriter, r *http.Request, remote string) {
|
||||
ctx := r.Context()
|
||||
VFS, err := s.getVFS(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, "File not found", http.StatusNotFound)
|
||||
@@ -247,7 +249,7 @@ func (s *HTTP) serveFile(w http.ResponseWriter, r *http.Request, remote string)
|
||||
http.Error(w, "File not found", http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
serve.Error(remote, w, "Failed to find file", err)
|
||||
serve.Error(ctx, remote, w, "Failed to find file", err)
|
||||
return
|
||||
}
|
||||
if !node.IsFile() {
|
||||
@@ -287,7 +289,7 @@ func (s *HTTP) serveFile(w http.ResponseWriter, r *http.Request, remote string)
|
||||
// open the object
|
||||
in, err := file.Open(os.O_RDONLY)
|
||||
if err != nil {
|
||||
serve.Error(remote, w, "Failed to open file", err)
|
||||
serve.Error(ctx, remote, w, "Failed to open file", err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
|
||||
@@ -349,6 +349,7 @@ func (w *WebDAV) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
// serveDir serves a directory index at dirRemote
|
||||
// This is similar to serveDir in serve http.
|
||||
func (w *WebDAV) serveDir(rw http.ResponseWriter, r *http.Request, dirRemote string) {
|
||||
ctx := r.Context()
|
||||
VFS, err := w.getVFS(r.Context())
|
||||
if err != nil {
|
||||
http.Error(rw, "Root directory not found", http.StatusNotFound)
|
||||
@@ -361,7 +362,7 @@ func (w *WebDAV) serveDir(rw http.ResponseWriter, r *http.Request, dirRemote str
|
||||
http.Error(rw, "Directory not found", http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
serve.Error(dirRemote, rw, "Failed to list directory", err)
|
||||
serve.Error(ctx, dirRemote, rw, "Failed to list directory", err)
|
||||
return
|
||||
}
|
||||
if !node.IsDir() {
|
||||
@@ -372,7 +373,7 @@ func (w *WebDAV) serveDir(rw http.ResponseWriter, r *http.Request, dirRemote str
|
||||
dirEntries, err := dir.ReadDirAll()
|
||||
|
||||
if err != nil {
|
||||
serve.Error(dirRemote, rw, "Failed to list directory", err)
|
||||
serve.Error(ctx, dirRemote, rw, "Failed to list directory", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user