From 67aace0024c8421c7419c02d488d48426eb2a6b0 Mon Sep 17 00:00:00 2001 From: Tugdual Saunier Date: Thu, 12 Jun 2025 11:42:37 +0200 Subject: [PATCH 1/2] do not truncate log files on each LogWriter calls We used to have a single concurrent usage of the `LogWriter`, but this is not the case anymore since b29665f7afcba0a71a30077d3516aa6076908924. Because of this we now loose the runner logs as he file is being truncated during the `buildCmd` call when the LogWrited is fetched. To fix this i propose to instantiate the LogWriter once which will effectively truncate the file only once per `server:start` launch. --- local/pid/pidfile.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/local/pid/pidfile.go b/local/pid/pidfile.go index db0ee4fd..3edf706a 100644 --- a/local/pid/pidfile.go +++ b/local/pid/pidfile.go @@ -49,6 +49,7 @@ type PidFile struct { CustomName string `json:"name"` path string + lw io.WriteCloser // log writer, used to write logs to the log file } func New(dir string, args []string) *PidFile { @@ -258,15 +259,24 @@ func (p *PidFile) LogReader() (io.ReadCloser, error) { } func (p *PidFile) LogWriter() (io.WriteCloser, error) { + // instantiate the log writer only once per process lifetime, this is useful + // to have a single truncate (and thus a clean log file) at the beginning of + // the process management but not truncate the log file when the process is + // restarted. + if p.lw != nil { + return p.lw, nil + } + logFile := p.LogFile() - if err := os.MkdirAll(filepath.Dir(logFile), 0755); err != nil { + err := os.MkdirAll(filepath.Dir(logFile), 0755) + if err != nil { return nil, err } - w, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) + p.lw, err = os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { return nil, err } - return w, nil + return p.lw, nil } func (p *PidFile) Binary() string { From 606fd41e3f88bd50266d406ac4921bd47f95e86c Mon Sep 17 00:00:00 2001 From: Tugdual Saunier Date: Sat, 14 Jun 2025 12:31:41 +0200 Subject: [PATCH 2/2] use sync.Once to make `PidFile.LogWriter` calls safe --- local/pid/pidfile.go | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/local/pid/pidfile.go b/local/pid/pidfile.go index 3edf706a..b044c8a0 100644 --- a/local/pid/pidfile.go +++ b/local/pid/pidfile.go @@ -27,6 +27,7 @@ import ( "os" "path/filepath" "strings" + "sync" "syscall" "time" @@ -49,7 +50,9 @@ type PidFile struct { CustomName string `json:"name"` path string - lw io.WriteCloser // log writer, used to write logs to the log file + + lwInit sync.Once // used to ensure that the log writer is only created once + lw io.WriteCloser // log writer, used to write logs to the log file } func New(dir string, args []string) *PidFile { @@ -258,25 +261,34 @@ func (p *PidFile) LogReader() (io.ReadCloser, error) { return r, nil } +// LogWriter returns a writer to write logs to the log file. It creates the log +// file if it does not exist, and truncates it if it does. It is safe to call +// this method multiple times, it will only create the log file once per process +// lifetime: it is useful to have a single truncation (and thus a clean log +// file) at the beginning of the process management but not to truncate the log +// file when the process is restarted. +// Please note this method might not return a writer even if the error is nil +// (the error is returned only for the first call). func (p *PidFile) LogWriter() (io.WriteCloser, error) { - // instantiate the log writer only once per process lifetime, this is useful - // to have a single truncate (and thus a clean log file) at the beginning of - // the process management but not truncate the log file when the process is - // restarted. - if p.lw != nil { - return p.lw, nil - } + var err error + + p.lwInit.Do(func() { + logFile := p.LogFile() + if err = errors.WithStack(os.MkdirAll(filepath.Dir(logFile), 0755)); err != nil { + return + } + p.lw, err = os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) + if err != nil { + err = errors.WithStack(err) + return + } + }) - logFile := p.LogFile() - err := os.MkdirAll(filepath.Dir(logFile), 0755) - if err != nil { - return nil, err - } - p.lw, err = os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { return nil, err } - return p.lw, nil + + return p.lw, err } func (p *PidFile) Binary() string {