diff options
author | Ola Bini <ola@autonomia.digital> | 2020-03-26 17:20:13 +0300 |
---|---|---|
committer | Ola Bini <ola@autonomia.digital> | 2020-03-26 17:20:13 +0300 |
commit | 8b2c7901ee2512c4adfd33ee59be5c3b787c05e7 (patch) | |
tree | e782356ffd4596b934430ee0aaf3d0661d808219 | |
parent | d6c4d9f766137c7115eaa38e7a6206bd087e091a (diff) |
Use MultiWriter to simplify the writing implementation. Also make it possible to initialize the log target to variable amounts of writers, and doesn't hardcode the use of StdErr as output
-rw-r--r-- | cmd/grumble/grumble.go | 2 | ||||
-rw-r--r-- | pkg/logtarget/logtarget.go | 52 |
2 files changed, 32 insertions, 22 deletions
diff --git a/cmd/grumble/grumble.go b/cmd/grumble/grumble.go index 04f87c7..139eadc 100644 --- a/cmd/grumble/grumble.go +++ b/cmd/grumble/grumble.go @@ -37,7 +37,7 @@ func main() { dataDir.Close() // Set up logging - logtarget.Default, err = logtarget.OpenFile(Args.LogPath) + logtarget.Default, err = logtarget.OpenFile(Args.LogPath, os.Stderr) if err != nil { fmt.Fprintf(os.Stderr, "Unable to open log file (%v): %v", Args.LogPath, err) return diff --git a/pkg/logtarget/logtarget.go b/pkg/logtarget/logtarget.go index 5cf99da..1b69a3b 100644 --- a/pkg/logtarget/logtarget.go +++ b/pkg/logtarget/logtarget.go @@ -21,57 +21,66 @@ type LogTarget interface { Rotate() error } -type fileLogTarget struct { +// logTarget is the default implementation of a log +// target. It can write to more than one writer at the same time +// but only rotate one file +type logTarget struct { mu sync.Mutex logfn string file *os.File + w io.Writer + ws []io.Writer } +// Default is the default log target for the application +// It has to be initialized before used var Default LogTarget +// OpenWriters returns a log target that will +// log to all the given writers at the same time +func OpenWriters(ws ...io.Writer) LogTarget { + target := &logTarget{} + target.w = io.MultiWriter(ws...) + return target +} + // OpenFile creates a LogTarget pointing to a log file // and returns it. // This method will open the file in append-only mode. -func OpenFile(fileName string) (t LogTarget, err error) { - target := &fileLogTarget{} +// It also takes a variable number of writers that are +// other log targets +func OpenFile(fileName string, ws ...io.Writer) (t LogTarget, err error) { + target := &logTarget{} target.logfn = fileName target.file, err = os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0650) if err != nil { return nil, err } + target.ws = ws + target.w = io.MultiWriter(append(ws, target.file)...) return target, nil } // Write writes a log message to all registered io.Writers -func (target *fileLogTarget) Write(in []byte) (int, error) { +func (target *logTarget) Write(out []byte) (int, error) { target.mu.Lock() defer target.mu.Unlock() - if target.file == nil { - panic("no log file opened") - } - - n, err := os.Stderr.Write(in) - if err != nil { - return n, err - } - - n, err = target.file.Write(in) - if err != nil { - return n, err - } - - return len(in), nil + return target.Write(out) } -// Rotate rotates the current log file. +// Rotate rotates the current log file, if one is opened. // This method holds a lock while rotating the log file, // and all log writes will be held back until the rotation // is complete. -func (target *fileLogTarget) Rotate() error { +func (target *logTarget) Rotate() error { target.mu.Lock() defer target.mu.Unlock() + if target.file == nil { + return nil + } + // Close the existing log file err := target.file.Close() if err != nil { @@ -82,6 +91,7 @@ func (target *fileLogTarget) Rotate() error { if err != nil { return err } + target.w = io.MultiWriter(append(target.ws, target.file)...) return nil } |