Files
gocryptotrader/log/logger_multiwriter.go
Ryan O'Hara-Reid ac692b04f4 log: fix bug, expand test coverage and slightly optimize (#847)
* log: fix bugs expand coverage and optimise

* log: fix linter issues

* log: fix linter issue and pack methods in same file

* log: drop defer

* logger: move global check inside getfields  and remove unused test function

* logger: Increase note thanks @gloriouscode

* logger: wrap error with writer type

* logger: change variable name

* logger: change variable names and remove validsublogger func as it doesn't add functionality over a standard map call

* logs: error when unsupported output is applied on setup calls

* logs: add glorious suggestion

* logger: add protection to reduce olympic gold medal races

* logger: fix linter issues

* log: glorious niterinos
2021-11-30 16:43:27 +11:00

92 lines
2.0 KiB
Go

package log
import (
"errors"
"fmt"
"io"
)
var (
errWriterAlreadyLoaded = errors.New("io.Writer already loaded")
errWriterNotFound = errors.New("io.Writer not found")
)
// Add appends a new writer to the multiwriter slice
func (mw *multiWriter) Add(writer io.Writer) error {
mw.mu.Lock()
defer mw.mu.Unlock()
for i := range mw.writers {
if mw.writers[i] == writer {
return errWriterAlreadyLoaded
}
}
mw.writers = append(mw.writers, writer)
return nil
}
// Remove removes existing writer from multiwriter slice
func (mw *multiWriter) Remove(writer io.Writer) error {
mw.mu.Lock()
defer mw.mu.Unlock()
for i := range mw.writers {
if mw.writers[i] != writer {
continue
}
mw.writers[i] = mw.writers[len(mw.writers)-1]
mw.writers[len(mw.writers)-1] = nil
mw.writers = mw.writers[:len(mw.writers)-1]
return nil
}
return errWriterNotFound
}
// Write concurrent safe Write for each writer
func (mw *multiWriter) Write(p []byte) (int, error) {
type data struct {
n int
err error
}
results := make(chan data, len(mw.writers))
mw.mu.RLock()
defer mw.mu.RUnlock()
for x := range mw.writers {
go func(w io.Writer, p []byte, ch chan<- data) {
n, err := w.Write(p)
if err != nil {
ch <- data{n, fmt.Errorf("%T %w", w, err)}
return
}
if n != len(p) {
ch <- data{n, fmt.Errorf("%T %w", w, io.ErrShortWrite)}
return
}
ch <- data{n, nil}
}(mw.writers[x], p, results)
}
for range mw.writers {
// NOTE: These results do not necessarily reflect the current io.writer
// due to the go scheduler and writer finishing at different times, the
// response coming from the channel might not match up with the for loop
// writer.
d := <-results
if d.err != nil {
return d.n, d.err
}
}
return len(p), nil
}
// MultiWriter make and return a new copy of multiWriter
func MultiWriter(writers ...io.Writer) (*multiWriter, error) {
mw := &multiWriter{}
for x := range writers {
err := mw.Add(writers[x])
if err != nil {
return nil, err
}
}
return mw, nil
}