From 5cebe53fa15ef110846e629c73822b7b2887935c Mon Sep 17 00:00:00 2001 From: MickaelK Date: Wed, 13 May 2026 12:24:33 +1000 Subject: [PATCH] feature (plg_backend_sftp): instrument sftp client --- server/plugin/plg_backend_sftp/index.go | 5 +- server/plugin/plg_backend_sftp/tracing.go | 87 +++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 server/plugin/plg_backend_sftp/tracing.go diff --git a/server/plugin/plg_backend_sftp/index.go b/server/plugin/plg_backend_sftp/index.go index 5e364588..b24089a7 100644 --- a/server/plugin/plg_backend_sftp/index.go +++ b/server/plugin/plg_backend_sftp/index.go @@ -17,7 +17,7 @@ var SftpCache AppCache type Sftp struct { SSHClient *ssh.Client - SFTPClient *sftp.Client + SFTPClient *tracedClient wg *sync.WaitGroup } @@ -74,6 +74,7 @@ func (s Sftp) Init(params map[string]string, app *App) (IBackend, error) { <-app.Context.Done() d.wg.Done() }() + d.SFTPClient.app = app return d, nil } @@ -184,7 +185,7 @@ func (s Sftp) Init(params map[string]string, app *App) (IBackend, error) { if err != nil { return &s, err } - s.SFTPClient = session + s.SFTPClient = &tracedClient{Client: session, app: app} s.wg = new(sync.WaitGroup) s.wg.Add(1) go func() { diff --git a/server/plugin/plg_backend_sftp/tracing.go b/server/plugin/plg_backend_sftp/tracing.go new file mode 100644 index 00000000..1d0017eb --- /dev/null +++ b/server/plugin/plg_backend_sftp/tracing.go @@ -0,0 +1,87 @@ +package plg_backend_sftp + +import ( + "os" + + . "github.com/mickael-kerjean/filestash/server/common" + "github.com/mickael-kerjean/filestash/server/pkg/tracer" + + "github.com/pkg/sftp" +) + +type tracedClient struct { + *sftp.Client + app *App +} + +func (t *tracedClient) ReadDir(path string) ([]os.FileInfo, error) { + span := NewSpan(t.app, "ReadDir", map[string]string{"sftp.path": path, "sftp.packet": "SSH_FXP_READDIR"}) + defer span.Close() + files, err := t.Client.ReadDir(path) + span.SetError(err) + return files, err +} + +func (t *tracedClient) OpenFile(path string, flags int) (*sftp.File, error) { + span := NewSpan(t.app, "OpenFile", map[string]string{"sftp.path": path, "sftp.packet": "SSH_FXP_OPEN"}) + defer span.Close() + f, err := t.Client.OpenFile(path, flags) + span.SetError(err) + return f, err +} + +func (t *tracedClient) Mkdir(path string) error { + span := NewSpan(t.app, "Mkdir", map[string]string{"sftp.path": path, "sftp.packet": "SSH_FXP_MKDIR"}) + defer span.Close() + err := t.Client.Mkdir(path) + span.SetError(err) + return err +} + +func (t *tracedClient) Remove(path string) error { + span := NewSpan(t.app, "Remove", map[string]string{"sftp.path": path, "sftp.packet": "SSH_FXP_REMOVE"}) + defer span.Close() + err := t.Client.Remove(path) + span.SetError(err) + return err +} + +func (t *tracedClient) RemoveDirectory(path string) error { + span := NewSpan(t.app, "RemoveDirectory", map[string]string{"sftp.path": path, "sftp.packet": "SSH_FXP_RMDIR"}) + defer span.Close() + err := t.Client.RemoveDirectory(path) + span.SetError(err) + return err +} + +func (t *tracedClient) Rename(from, to string) error { + span := NewSpan(t.app, "Rename", map[string]string{"sftp.from": from, "sftp.to": to, "sftp.packet": "SSH_FXP_RENAME"}) + defer span.Close() + err := t.Client.Rename(from, to) + span.SetError(err) + return err +} + +func (t *tracedClient) Stat(path string) (os.FileInfo, error) { + span := NewSpan(t.app, "Stat", map[string]string{"sftp.path": path, "sftp.packet": "SSH_FXP_STAT"}) + defer span.Close() + f, err := t.Client.Stat(path) + span.SetError(err) + return f, err +} + +func (t *tracedClient) Getwd() (string, error) { + span := NewSpan(t.app, "Getwd", map[string]string{"sftp.packet": "SSH_FXP_REALPATH"}) + defer span.Close() + cwd, err := t.Client.Getwd() + span.SetError(err) + return cwd, err +} + +func NewSpan(app *App, name string, attrs map[string]string) tracer.ISpan { + return tracer.StartSpan(tracer.TraceFromContext(app.Context), name, tracer.SpanOptions{ + Kind: tracer.KindClient, + Service: "sftp", + Attributes: attrs, + }) +}