Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trace Support #284

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"os"
"runtime"
"time"
)

Expand All @@ -29,13 +30,17 @@ type Entry struct {

// Message passed to Debug, Info, Warn, Error, Fatal or Panic
Message string

// Trace information
Trace string
}

func NewEntry(logger *Logger) *Entry {
return &Entry{
Logger: logger,
// Default is three fields, give a little extra room
Data: make(Fields, 5),
Data: make(Fields, 5),
Trace: "",
}
}

Expand Down Expand Up @@ -78,13 +83,26 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
return &Entry{Logger: entry.Logger, Data: data}
}

// WithTrace adds a stack trace back from where the log entry was created
func (entry *Entry) WithTrace() *Entry {
// don't actually do the trace here otherwise it'll be wrong
entry.Trace = "placeholder"
return entry
}

// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {
entry.Time = time.Now()
entry.Level = level
entry.Message = msg

if entry.Trace == "placeholder" {
stack := make([]byte, 2048)
size := runtime.Stack(stack, false)
entry.Trace = string(stack[:size])
}

if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
Expand Down
5 changes: 5 additions & 0 deletions formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,9 @@ func prefixFieldClashes(data Fields) {
if ok {
data["fields.level"] = data["level"]
}

_, ok = data["trace"]
if ok {
data["fields.trace"] = data["trace"]
}
}
5 changes: 5 additions & 0 deletions json_formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data["msg"] = entry.Message
data["level"] = entry.Level.String()

// Only add trace if it was built
if entry.Trace != "" {
data["trace"] = entry.Trace
}

serialized, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
Expand Down
5 changes: 5 additions & 0 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ func (logger *Logger) WithFields(fields Fields) *Entry {
return NewEntry(logger).WithFields(fields)
}

// WithTrace creates a new log entry with a captured trace from the current location
func (logger *Logger) WithTrace() *Entry {
return NewEntry(logger).WithTrace()
}

func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debugf(format, args...)
Expand Down
13 changes: 13 additions & 0 deletions logrus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func TestPrint(t *testing.T) {
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
assert.Equal(t, fields["level"], "info")
assert.Nil(t, fields["trace"])
})
}

Expand All @@ -71,6 +72,7 @@ func TestInfo(t *testing.T) {
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
assert.Equal(t, fields["level"], "info")
assert.Nil(t, fields["trace"])
})
}

Expand All @@ -80,6 +82,17 @@ func TestWarn(t *testing.T) {
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
assert.Equal(t, fields["level"], "warning")
assert.Nil(t, fields["trace"])
})
}

func TestWithTrace(t *testing.T) {
LogAndAssertJSON(t, func(log *Logger) {
log.WithTrace().Warn("test")
}, func(fields Fields) {
assert.Equal(t, fields["msg"], "test")
assert.Equal(t, fields["level"], "warning")
assert.NotNil(t, fields["trace"])
})
}

Expand Down