Skip to content

Commit

Permalink
fix: add backtrace support
Browse files Browse the repository at this point in the history
fix: improve further on tests, log-level parsing should be more robust.
  • Loading branch information
perbu committed Sep 19, 2022
1 parent 9341bad commit 079a238
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 85 deletions.
32 changes: 21 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,30 @@ A field is a `Pair` consisting of a key, `string` and value, `interface{}`.
You can choose to instantiate a logger. Doing this will allow you to set a
name as well as to add some fields to the logger.
#### without a logger instance.
```go
chainsaw.Infof("Application %f starting up", version)
if err!= nil {
chainsaw.Fatal("Out of gloop")
}
// with fields:
chainsaw.Infow("Can't open file",chainsaw.P{"file", file}, chainsaw.P{"err", err})
```
package main
import "github.com/celerway/chainsaw"
func main() {
chainsaw.Infof("Application %f starting up", version)
err := checkGloop()
if err != nil {
chainsaw.Fatal("Out of gloop")
}
// with fields:
chainsaw.Infow("Can't open file", chainsaw.P{"file", file}, chainsaw.P{"err", err})
}
```
#### with a logger instance.
```go
```
package main
import "github.com/celerway/chainsaw"
logger := chainsaw.MakeLogger("main")
logger.SetFields(chainsaw.P{"hostname", hostname})
logger.Error("Error in file:", err)
func main() {
logger := chainsaw.MakeLogger("main")
logger.SetFields(chainsaw.P{"hostname", hostname})
logger.Error("Error in file:", err)
}
}
```

Expand Down
26 changes: 14 additions & 12 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func MakeLogger(name string, options ...int) *CircularLogger {
chanBufferSize: chanBufferSize,
outputWriters: []io.Writer{os.Stdout},
TimeFmt: "2006-01-02T15:04:05-0700",
backTraceLevel: TraceLevel,
}
go c.channelHandler()
runtime.Gosched()
Expand Down Expand Up @@ -112,12 +113,13 @@ func GetMessages(level LogLevel) []LogMessage {
return l.GetMessages(level)
}

// BackTrace logs messages from the current buffer to the log file.
// This happens in one single write so it'll be continuous in the logs.
// Todo: finish this. Needs to have formatting stuff done first, which needs the structured bits to work.
func BackTrace() error {
func SetBackTraceLevel(level LogLevel) {
l := defaultLogger
l.SetBackTraceLevel(level)
}

return nil
func (l *CircularLogger) SetBackTraceLevel(level LogLevel) {
l.backTraceLevel = level
}

// SetLevel sets the log level. This affects if messages are printed to
Expand Down Expand Up @@ -186,15 +188,15 @@ func GetLevels() []LogLevel {
return levels
}

func ParseLogLevel(s string) LogLevel {
level := InfoLevel
func ParseLogLevel(s string) (LogLevel, error) {
s = strings.ToLower(s)
s = strings.TrimSuffix(s, "level")
for l := TraceLevel; l <= FatalLevel; l++ {
cmpLevel := strings.ToLower(l.String())
if cmpLevel == s {
level = l
break
s2 := strings.ToLower(l.String())
s2 = strings.TrimSuffix(s2, "level")
if s2 == s {
return l, nil
}
}
return level
return 0, fmt.Errorf("invalid log level: %s", s)
}
91 changes: 72 additions & 19 deletions api_test.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,89 @@
package chainsaw

import "testing"
import (
"bytes"
"fmt"
is2 "github.com/matryer/is"
"os"
"testing"
"time"
)

func TestParseLogLevel(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want LogLevel
name string
args args
want LogLevel
wantErr bool
}{
{"trace", args{"trace"}, TraceLevel},
{"debug", args{"debug"}, DebugLevel},
{"info", args{"info"}, InfoLevel},
{"warn", args{"warn"}, WarnLevel},
{"error", args{"error"}, ErrorLevel},
{"fatal", args{"fatal"}, FatalLevel},
{"traceUpper", args{"TRACE"}, TraceLevel},
{"debugUpper", args{"DEBUG"}, DebugLevel},
{"infoUpper", args{"INFO"}, InfoLevel},
{"warnUpper", args{"WARN"}, WarnLevel},
{"errorUpper", args{"ERROR"}, ErrorLevel},
{"fatalUpper", args{"FATAL"}, FatalLevel},
{"empty", args{""}, InfoLevel},
{"invalid", args{"blalbla"}, InfoLevel},
{"trace", args{"trace"}, TraceLevel, false},
{"debug", args{"debug"}, DebugLevel, false},
{"info", args{"info"}, InfoLevel, false},
{"warn", args{"warn"}, WarnLevel, false},
{"error", args{"error"}, ErrorLevel, false},
{"fatal", args{"fatal"}, FatalLevel, false},
{"tracelevel", args{"tracelevel"}, TraceLevel, false},
{"debuglevel", args{"debuglevel"}, DebugLevel, false},
{"infolevel", args{"infolevel"}, InfoLevel, false},
{"warnlevel", args{"warnlevel"}, WarnLevel, false},
{"errorlevel", args{"errorlevel"}, ErrorLevel, false},
{"fatallevel", args{"fatallevel"}, FatalLevel, false},
{"traceUpper", args{"TRACE"}, TraceLevel, false},
{"debugUpper", args{"DEBUG"}, DebugLevel, false},
{"infoUpper", args{"INFO"}, InfoLevel, false},
{"warnUpper", args{"WARN"}, WarnLevel, false},
{"errorUpper", args{"ERROR"}, ErrorLevel, false},
{"fatalUpper", args{"FATAL"}, FatalLevel, false},
{"empty", args{""}, InfoLevel, true},
{"invalid", args{"blalbla"}, InfoLevel, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ParseLogLevel(tt.args.s); got != tt.want {
got, err := ParseLogLevel(tt.args.s)
if (err != nil) != tt.wantErr {
t.Errorf("ParseLogLevel() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && got != tt.want {
t.Errorf("ParseLogLevel() = %v, want %v", got, tt.want)
}
})
}
}

func TestCircularLogger_BackTrace(t *testing.T) {
is := is2.New(t)

logger := MakeLogger("", 30, 10)
err := logger.RemoveWriter(os.Stdout)
is.NoErr(err)
logger.SetBackTraceLevel(ErrorLevel)
logger.SetLevel(ErrorLevel)
logBuffer := bytes.NewBuffer(make([]byte, 0, 1024))
err = logger.AddWriter(logBuffer)
is.NoErr(err)

logger.Trace("trace")
logger.Debug("debug")
logger.Info("info")
logger.Warn("warn")
logger.Error("error")
err = logger.Flush() // trigger a flush, so we know things are flushed out to the buffer
is.NoErr(err)
time.Sleep(time.Millisecond)
lines := bytes.Split(logBuffer.Bytes(), []byte{'\n'})
for i, line := range lines {
fmt.Printf("line %d: %s\n", i, line)
}
is.True(bytes.Contains(lines[0], []byte("error")))
is.True(bytes.Contains(lines[1], []byte("backtrace begin")))
is.True(bytes.Contains(lines[2], []byte("trace")))
is.True(bytes.Contains(lines[3], []byte("debug")))
is.True(bytes.Contains(lines[4], []byte("info")))
is.True(bytes.Contains(lines[5], []byte("warn")))
is.True(bytes.Contains(lines[6], []byte("error")))
is.True(bytes.Contains(lines[7], []byte("backtrace end")))
}
32 changes: 32 additions & 0 deletions controltype_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions loglevel_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 079a238

Please sign in to comment.