1
0
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:
Benjamin Legrand
2021-12-08 17:14:45 +01:00
committed by Nick Craig-Wood
parent c053429b9c
commit 8a6fc8535d
19 changed files with 139 additions and 86 deletions

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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() {

View File

@@ -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
}