Skip to content

Commit

Permalink
WIP: A new implementation of MultiWriters
Browse files Browse the repository at this point in the history
  • Loading branch information
suzaku committed Aug 14, 2020
1 parent f5b2be8 commit b23266f
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
6 changes: 5 additions & 1 deletion logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ type Logger struct {

// Writer specifies the writer of output. It uses os.Stderr in if empty.
Writer io.Writer

Writers *MultiWriter
}

const (
Expand Down Expand Up @@ -283,7 +285,9 @@ func (l *Logger) header(level Level) *Event {
e.exit = false
e.panic = true
}
if l.Writer != nil {
if l.Writers != nil {
e.w = l.Writers.CombineWriters(level)
} else if l.Writer != nil {
e.w = l.Writer
} else {
e.w = os.Stderr
Expand Down
35 changes: 35 additions & 0 deletions multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ import (
"io"
)

type CombineWriter []io.Writer

func (cw CombineWriter) Write(p []byte) (n int, firstErr error) {
for _, w := range cw {
var err error
n, err = w.Write(p)
if err != nil && firstErr == nil {
firstErr = err
}
}
return n, firstErr
}

var _ io.Writer = CombineWriter{}

// MultiWriter is an io.WriteCloser that log to different writers by different levels
type MultiWriter struct {
// InfoWriter specifies the level large than info logs writes to
Expand All @@ -31,6 +46,26 @@ type MultiWriter struct {
// ParseLevel: func([]byte) log.Level { return log.ParseLevel(string(p[49])) },
// }
ParseLevel func([]byte) Level

writers []*io.Writer
}

func (w *MultiWriter) CombineWriters(level Level) CombineWriter {
// TODO: The fixed number of combinations can be cached to avoid unnecessary allocations
var cw CombineWriter
if level>= ErrorLevel && w.ErrorWriter != nil {
cw = append(cw, w.ErrorWriter)
}
if level >= WarnLevel && w.WarnWriter != nil {
cw = append(cw, w.WarnWriter)
}
if w.InfoWriter != nil {
cw = append(cw, w.InfoWriter)
}
if w.StderrWriter != nil && level >= w.StderrLevel {
cw = append(cw, w.StderrWriter)
}
return cw
}

// Close implements io.Closer, and closes the underlying Writers.
Expand Down
43 changes: 43 additions & 0 deletions multi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,49 @@ import (
"testing"
)

func TestNewMultiWriters(t *testing.T) {
// TODO: Use mock writers to validate that the logs are routed correctly
w := &MultiWriter{
InfoWriter: &FileWriter{
Filename: "file-info.log",
},
WarnWriter: &FileWriter{
Filename: "file-warn.log",
},
ErrorWriter: &FileWriter{
Filename: "file-error.log",
},
}
logger := Logger{
Level: InfoLevel,
Caller: 1,
Writers: w,
}
assertNLogs := func (want int) {
matches, _ := filepath.Glob("file-*.*.log")
if len(matches) != want {
t.Fatalf("filepath glob return %+v number mismatch, got %+v want %+v", matches, len(matches), want)
}
}

logger.Info().Int("id", 42).Msg("I'm loving it.")
assertNLogs(1)

logger.Warn().Int("id", 43).Msg("I double dare you.")
assertNLogs(2)

logger.Error().Str("action", "cleanup").Msg("World")
assertNLogs(3)

matches, _ := filepath.Glob("file-*.log")
for i := range matches {
err := os.Remove(matches[i])
if err != nil {
t.Fatalf("os remove %s error: %+v", matches[i], err)
}
}
}

func TestMultiWriter(t *testing.T) {
w := &MultiWriter{
InfoWriter: &FileWriter{
Expand Down

0 comments on commit b23266f

Please sign in to comment.