From 138d48f2ff30aabbb9e69ebf17219e1661ab0a42 Mon Sep 17 00:00:00 2001 From: Paul Rosania Date: Thu, 29 Oct 2015 17:11:36 -0700 Subject: [PATCH 1/7] Restore stack trace logging This patch restores stack trace logging. It avoids parsing stack trace text, opting for runtime.Callers and runtime.FuncForPC instead. Support for overriding the stack trace by setting KeyMap.CallStack was removed. This only worked in happyDevFormatter, and would have triggered a warning anyway, since it's a reserved key. --- v1/callstack.go | 126 ++++++++++------------------------------ v1/happyDevFormatter.go | 11 ++-- 2 files changed, 36 insertions(+), 101 deletions(-) diff --git a/v1/callstack.go b/v1/callstack.go index 208eb40..a37af48 100644 --- a/v1/callstack.go +++ b/v1/callstack.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "strconv" "strings" @@ -20,6 +21,7 @@ type frameInfo struct { filename string lineno int method string + pc uintptr context []*sourceLine contextLines int } @@ -145,117 +147,53 @@ func (ci *frameInfo) String(color string, sourceColor string) string { return buf.String() } -// parseDebugStack parases a stack created by debug.Stack() -// -// This is what the string looks like -// /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:45 (0x5fa70) -// (*JSONFormatter).writeError: jf.writeString(buf, err.Error()+"\n"+string(debug.Stack())) -// /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:82 (0x5fdc3) -// (*JSONFormatter).appendValue: jf.writeError(buf, err) -// /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:109 (0x605ca) -// (*JSONFormatter).set: jf.appendValue(buf, val) -// ... -// /Users/mgutz/goroot/src/runtime/asm_amd64.s:2232 (0x38bf1) -// goexit: -func parseDebugStack(stack string, skip int, ignoreRuntime bool) []*frameInfo { +// Generates a stack from runtime.Callers() +func stackFrames(skip int, ignoreRuntime bool) []*frameInfo { frames := []*frameInfo{} - // BUG temporarily disable since there is a bug with embedded newlines - if true { - return frames - } - - lines := strings.Split(stack, "\n") - - for i := skip * 2; i < len(lines); i += 2 { - ci := &frameInfo{} - sourceLine := lines[i] - if sourceLine == "" { - break - } - if ignoreRuntime && strings.Contains(sourceLine, filepath.Join("src", "runtime")) { + size := 20 + pcs := make([]uintptr, size) + // always skip the first frame, since it's runtime.Callers itself + pcs = pcs[:runtime.Callers(1+skip, pcs)] + + for _, pc := range pcs { + fn := runtime.FuncForPC(pc) + name := fn.Name() + file, line := fn.FileLine(pc - 1) + if ignoreRuntime && strings.Contains(file, filepath.Join("src", "runtime")) { break } - colon := strings.Index(sourceLine, ":") - slash := strings.Index(sourceLine, "/") - if colon < slash { - // must be on Windows where paths look like c:/foo/bar.go:lineno - colon = strings.Index(sourceLine[slash:], ":") + slash + ci := &frameInfo{ + filename: file, + lineno: line, + method: name, + pc: pc, } - space := strings.Index(sourceLine, " ") - ci.filename = sourceLine[0:colon] - // BUG with callstack where the error message has embedded newlines - // if colon > space { - // fmt.Println("lines", lines) - // } - // fmt.Println("SOURCELINE", sourceLine, "len", len(sourceLine), "COLON", colon, "SPACE", space) - numstr := sourceLine[colon+1 : space] - lineno, err := strconv.Atoi(numstr) - if err != nil { - InternalLog.Warn("Could not parse line number", "sourceLine", sourceLine, "numstr", numstr) - continue - } - ci.lineno = lineno - - methodLine := lines[i+1] - colon = strings.Index(methodLine, ":") - ci.method = strings.Trim(methodLine[0:colon], "\t ") frames = append(frames, ci) } return frames } -// parseDebugStack parases a stack created by debug.Stack() -// -// This is what the string looks like -// /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:45 (0x5fa70) -// (*JSONFormatter).writeError: jf.writeString(buf, err.Error()+"\n"+string(debug.Stack())) -// /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:82 (0x5fdc3) -// (*JSONFormatter).appendValue: jf.writeError(buf, err) -// /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:109 (0x605ca) -// (*JSONFormatter).set: jf.appendValue(buf, val) -// ... -// /Users/mgutz/goroot/src/runtime/asm_amd64.s:2232 (0x38bf1) -// goexit: -func trimDebugStack(stack string) string { +// Returns debug stack excluding logxi frames +func trimmedStackTrace() string { buf := pool.Get() defer pool.Put(buf) - lines := strings.Split(stack, "\n") - for i := 0; i < len(lines); i += 2 { - sourceLine := lines[i] - if sourceLine == "" { - break - } - - colon := strings.Index(sourceLine, ":") - slash := strings.Index(sourceLine, "/") - if colon < slash { - // must be on Windows where paths look like c:/foo/bar.go:lineno - colon = strings.Index(sourceLine[slash:], ":") + slash - } - filename := sourceLine[0:colon] + frames := stackFrames(0, false) + for _, frame := range frames { // skip anything in the logxi package - if isLogxiCode(filename) { + if isLogxiCode(frame.filename) { continue } - buf.WriteString(sourceLine) - buf.WriteRune('\n') - buf.WriteString(lines[i+1]) - buf.WriteRune('\n') - } - return buf.String() -} -func parseLogxiStack(entry map[string]interface{}, skip int, ignoreRuntime bool) []*frameInfo { - kv := entry[KeyMap.CallStack] - if kv == nil { - return nil - } + fmt.Fprintf(buf, "%s:%d (0x%x)\n", frame.filename, frame.lineno, frame.pc) - var frames []*frameInfo - if stack, ok := kv.(string); ok { - frames = parseDebugStack(stack, skip, ignoreRuntime) + err := frame.readSource(0) + if err != nil || len(frame.context) < 1 { + continue + } + + fmt.Fprintf(buf, "\t%s: %s\n", frame.method, frame.context[0].line) } - return frames + return buf.String() } diff --git a/v1/happyDevFormatter.go b/v1/happyDevFormatter.go index 3931b36..5e25490 100644 --- a/v1/happyDevFormatter.go +++ b/v1/happyDevFormatter.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "runtime/debug" "strings" "github.com/mgutz/ansi" @@ -175,7 +174,7 @@ func (hd *HappyDevFormatter) getContext(color string) string { if disableCallstack { return "" } - frames := parseDebugStack(string(debug.Stack()), 5, true) + frames := stackFrames(7, true) if len(frames) == 0 { return "" } @@ -220,17 +219,15 @@ func (hd *HappyDevFormatter) getLevelContext(level int, entry map[string]interfa } if disableCallstack || contextLines == -1 { - context = trimDebugStack(string(debug.Stack())) + context = trimmedStackTrace() break } - frames := parseLogxiStack(entry, 4, true) - if frames == nil { - frames = parseDebugStack(string(debug.Stack()), 4, true) - } + frames := stackFrames(6, true) if len(frames) == 0 { break } + errbuf := pool.Get() defer pool.Put(errbuf) lines := 0 From 105a88a66c5e9b625e51c20a18c1cd1e6b823dd8 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Fri, 4 Dec 2015 07:48:47 -0500 Subject: [PATCH 2/7] Default to STDERR instead of STDOUT --- v1/defaultLogger.go | 2 +- v1/init.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/v1/defaultLogger.go b/v1/defaultLogger.go index 40fb513..38bd8cb 100644 --- a/v1/defaultLogger.go +++ b/v1/defaultLogger.go @@ -52,7 +52,7 @@ func NewLogger3(writer io.Writer, name string, formatter Formatter) Logger { // New creates a colorable default logger. func New(name string) Logger { - return NewLogger(colorableStdout, name) + return NewLogger(colorableStderr, name) } // Trace logs a debug entry. diff --git a/v1/init.go b/v1/init.go index 57c9140..c4456a4 100644 --- a/v1/init.go +++ b/v1/init.go @@ -68,7 +68,7 @@ var logxiNameLevelMap map[string]int // logxiFormat is the formatter kind to create var logxiFormat string -var colorableStdout io.Writer +var colorableStderr io.Writer var defaultContextLines = 2 var defaultFormat string var defaultLevel int @@ -144,7 +144,7 @@ func setDefaults(isTerminal bool) { if os.Getenv("ConEmuANSI") == "ON" { defaultLogxiColorsEnv = "key=cyan+h,value,misc=blue+h,source=yellow,TRC,DBG,WRN=yellow+h,INF=green+h,ERR=red+h" } else { - colorableStdout = NewConcurrentWriter(colorable.NewColorableStdout()) + colorableStderr = NewConcurrentWriter(colorable.NewColorableStderr()) defaultLogxiColorsEnv = "ERR=red,misc=cyan,key=cyan" } // DefaultScheme is a color scheme optimized for dark background @@ -176,15 +176,15 @@ func isReservedKey(k interface{}) (bool, error) { } func init() { - colorableStdout = NewConcurrentWriter(os.Stdout) + colorableStderr = NewConcurrentWriter(os.Stderr) - isTerminal = isatty.IsTerminal(os.Stdout.Fd()) + isTerminal = isatty.IsTerminal(os.Stderr.Fd()) // the internal logger to report errors if isTerminal { - InternalLog = NewLogger3(NewConcurrentWriter(os.Stdout), "__logxi", NewTextFormatter("__logxi")) + InternalLog = NewLogger3(NewConcurrentWriter(os.Stderr), "__logxi", NewTextFormatter("__logxi")) } else { - InternalLog = NewLogger3(NewConcurrentWriter(os.Stdout), "__logxi", NewJSONFormatter("__logxi")) + InternalLog = NewLogger3(NewConcurrentWriter(os.Stderr), "__logxi", NewJSONFormatter("__logxi")) } InternalLog.SetLevel(LevelError) From 96fff1be642e6c338805e9579a1b5fc23391c532 Mon Sep 17 00:00:00 2001 From: Russ Egan Date: Wed, 24 Feb 2016 18:56:57 -0500 Subject: [PATCH 3/7] fixes coloring of source context lines the ci.contextLines is never set (nor was it set in any prior version I could find), but the global contextLines var seems to have the right info. Also: - use the current line marker even when the context is one. This is useful when colors are disabled. - if source context line color is default, the color of the previous line was bleeding over. Need to reset the color on each source line. - found a couple more places where disableColors wasn't being honored --- v1/callstack.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/v1/callstack.go b/v1/callstack.go index a37af48..2b22b5c 100644 --- a/v1/callstack.go +++ b/v1/callstack.go @@ -99,7 +99,7 @@ func (ci *frameInfo) String(color string, sourceColor string) string { buf.WriteString(strconv.Itoa(ci.lineno)) buf.WriteString(")") - if ci.contextLines == -1 { + if contextLines == -1 { return buf.String() } buf.WriteString("\n") @@ -120,17 +120,26 @@ func (ci *frameInfo) String(color string, sourceColor string) string { } for _, li := range ci.context { + if !disableColors { + // need to reset here. If source is set to default color, then the message + // color will bleed over into the source context lines + buf.WriteString(ansi.Reset) + } var format string format = fmt.Sprintf("%%s%%%dd: %%s\n", linenoWidth) if li.lineno == ci.lineno { - buf.WriteString(color) - if ci.contextLines > 2 { + if !disableColors { + buf.WriteString(color) + } + if contextLines > 0 { format = fmt.Sprintf("%%s=> %%%dd: %%s\n", linenoWidth) } } else { - buf.WriteString(sourceColor) - if ci.contextLines > 2 { + if !disableColors { + buf.WriteString(sourceColor) + } + if contextLines > 0 { // account for "=> " format = fmt.Sprintf("%%s%%%dd: %%s\n", linenoWidth+3) } From ea65a6b51f5b2a13882c27debf570772e52488d5 Mon Sep 17 00:00:00 2001 From: Russ Egan Date: Fri, 26 Feb 2016 11:17:28 -0500 Subject: [PATCH 4/7] when showing source as log value, use the value theme color --- v1/happyDevFormatter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1/happyDevFormatter.go b/v1/happyDevFormatter.go index 5e25490..5257c26 100644 --- a/v1/happyDevFormatter.go +++ b/v1/happyDevFormatter.go @@ -348,7 +348,7 @@ func (hd *HappyDevFormatter) Format(writer io.Writer, level int, msg string, arg if level == LevelTrace || (level == LevelWarn && !hasCallStack) { // gets rid of "in " idx := strings.IndexRune(context, 'n') - hd.set(buf, "in", context[idx+2:], color) + hd.set(buf, "in", context[idx+2:], theme.Value) } else { buf.WriteRune('\n') if !disableColors { From 845472dd0fe0878345ad809a0829361b26386763 Mon Sep 17 00:00:00 2001 From: Russ Egan Date: Tue, 24 May 2016 09:16:21 -0400 Subject: [PATCH 5/7] fix data races multiple go routines can use a formatter concurrently, and the writes to the formatter's "col" attribute were not synchronized. Instead, create a local col var for each log write. --- v1/happyDevFormatter.go | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/v1/happyDevFormatter.go b/v1/happyDevFormatter.go index 5257c26..8bb3160 100644 --- a/v1/happyDevFormatter.go +++ b/v1/happyDevFormatter.go @@ -110,7 +110,6 @@ func parseTheme(theme string) *colorScheme { // works fine in SSH terminals and binary deployments. type HappyDevFormatter struct { name string - col int // always use the production formatter jsonFormatter *JSONFormatter } @@ -124,21 +123,21 @@ func NewHappyDevFormatter(name string) *HappyDevFormatter { } } -func (hd *HappyDevFormatter) writeKey(buf bufferWriter, key string) { +func (hd *HappyDevFormatter) writeKey(buf bufferWriter, key string, col *int) { // assumes this is not the first key - hd.writeString(buf, Separator) + hd.writeString(buf, Separator, col) if key == "" { return } buf.WriteString(theme.Key) - hd.writeString(buf, key) - hd.writeString(buf, AssignmentChar) + hd.writeString(buf, key, col) + hd.writeString(buf, AssignmentChar, col) if !disableColors { buf.WriteString(ansi.Reset) } } -func (hd *HappyDevFormatter) set(buf bufferWriter, key string, value interface{}, color string) { +func (hd *HappyDevFormatter) set(buf bufferWriter, key string, value interface{}, color string, col *int) { var str string if s, ok := value.(string); ok { str = s @@ -148,16 +147,16 @@ func (hd *HappyDevFormatter) set(buf bufferWriter, key string, value interface{} str = fmt.Sprintf("%v", value) } val := strings.Trim(str, "\n ") - if (isPretty && key != "") || hd.col+len(key)+2+len(val) >= maxCol { + if (isPretty && key != "") || *col+len(key)+2+len(val) >= maxCol { buf.WriteString("\n") - hd.col = 0 - hd.writeString(buf, indent) + *col = 0 + hd.writeString(buf, indent, col) } - hd.writeKey(buf, key) + hd.writeKey(buf, key, col) if color != "" { buf.WriteString(color) } - hd.writeString(buf, val) + hd.writeString(buf, val, col) if color != "" && !disableColors { buf.WriteString(ansi.Reset) } @@ -165,9 +164,9 @@ func (hd *HappyDevFormatter) set(buf bufferWriter, key string, value interface{} // Write a string and tracks the position of the string so we can break lines // cleanly. Do not send ANSI escape sequences, just raw strings -func (hd *HappyDevFormatter) writeString(buf bufferWriter, s string) { +func (hd *HappyDevFormatter) writeString(buf bufferWriter, s string, col *int) { buf.WriteString(s) - hd.col += len(s) + *col += len(s) } func (hd *HappyDevFormatter) getContext(color string) string { @@ -291,11 +290,11 @@ func (hd *HappyDevFormatter) Format(writer io.Writer, level int, msg string, arg entry := hd.jsonFormatter.LogEntry(level, msg, args) // reset the column tracker used for fancy formatting - hd.col = 0 + col := 0 // timestamp buf.WriteString(theme.Misc) - hd.writeString(buf, entry[KeyMap.Time].(string)) + hd.writeString(buf, entry[KeyMap.Time].(string), &col) if !disableColors { buf.WriteString(ansi.Reset) } @@ -307,11 +306,11 @@ func (hd *HappyDevFormatter) Format(writer io.Writer, level int, msg string, arg } // DBG, INF ... - hd.set(buf, "", entry[KeyMap.Level].(string), color) + hd.set(buf, "", entry[KeyMap.Level].(string), color, &col) // logger name - hd.set(buf, "", entry[KeyMap.Name], theme.Misc) + hd.set(buf, "", entry[KeyMap.Name], theme.Misc, &col) // message from user - hd.set(buf, "", message, theme.Message) + hd.set(buf, "", message, theme.Message, &col) // Preserve key order in the sequencethey were added by developer.This // makes it easier for developers to follow the log. @@ -336,7 +335,7 @@ func (hd *HappyDevFormatter) Format(writer io.Writer, level int, msg string, arg } else if isReserved { continue } - hd.set(buf, key, entry[key], theme.Value) + hd.set(buf, key, entry[key], theme.Value, &col) } addLF := true @@ -348,7 +347,7 @@ func (hd *HappyDevFormatter) Format(writer io.Writer, level int, msg string, arg if level == LevelTrace || (level == LevelWarn && !hasCallStack) { // gets rid of "in " idx := strings.IndexRune(context, 'n') - hd.set(buf, "in", context[idx+2:], theme.Value) + hd.set(buf, "in", context[idx+2:], theme.Value, &col) } else { buf.WriteRune('\n') if !disableColors { @@ -361,7 +360,7 @@ func (hd *HappyDevFormatter) Format(writer io.Writer, level int, msg string, arg } } } else if hasCallStack { - hd.set(buf, "", entry[KeyMap.CallStack], color) + hd.set(buf, "", entry[KeyMap.CallStack], color, &col) } if addLF { buf.WriteRune('\n') From e13d246a5f884532aacb139930f581c09abff965 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Wed, 24 Aug 2016 15:51:20 -0400 Subject: [PATCH 6/7] Adds an RFC5424 formatter. Fixed logger registration bug --- v1/bench/bench_test.go | 3 +- v1/cmd/demo/main.go | 2 +- v1/cmd/filter/main.go | 2 +- v1/cmd/reldir/foo.go | 2 +- v1/formatter.go | 2 + v1/init.go | 1 + v1/logger.go | 2 + v1/rfc5424Formatter.go | 94 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 v1/rfc5424Formatter.go diff --git a/v1/bench/bench_test.go b/v1/bench/bench_test.go index 924650f..11079c0 100644 --- a/v1/bench/bench_test.go +++ b/v1/bench/bench_test.go @@ -7,8 +7,7 @@ import ( "testing" "github.com/Sirupsen/logrus" - "github.com/mgutz/logxi/v1" - "gopkg.in/inconshreveable/log15.v2" + "github.com/serussell/logxi/v1" ) type M map[string]interface{} diff --git a/v1/cmd/demo/main.go b/v1/cmd/demo/main.go index 82ab062..4d3a4e1 100644 --- a/v1/cmd/demo/main.go +++ b/v1/cmd/demo/main.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/mgutz/logxi/v1" + "github.com/serussell/logxi/v1" ) var errConfig = fmt.Errorf("file not found") diff --git a/v1/cmd/filter/main.go b/v1/cmd/filter/main.go index 33492ed..ca7e464 100644 --- a/v1/cmd/filter/main.go +++ b/v1/cmd/filter/main.go @@ -7,7 +7,7 @@ import ( "io" "os" - "github.com/mgutz/logxi/v1" + "github.com/serussell/logxi/v1" ) func sendExternal(obj map[string]interface{}) { diff --git a/v1/cmd/reldir/foo.go b/v1/cmd/reldir/foo.go index 7729f2f..3a19553 100644 --- a/v1/cmd/reldir/foo.go +++ b/v1/cmd/reldir/foo.go @@ -1,6 +1,6 @@ package reldir -import "github.com/mgutz/logxi/v1" +import "github.com/serussell/logxi/v1" // Foo returns error func Foo() { diff --git a/v1/formatter.go b/v1/formatter.go index 9357394..4863429 100644 --- a/v1/formatter.go +++ b/v1/formatter.go @@ -45,6 +45,8 @@ func formatFactory(name string, kind string) (Formatter, error) { formatter = NewTextFormatter(name) case FormatJSON: formatter = NewJSONFormatter(name) + case FormatRFC5424: + formatter = NewRFC5424Formatter(name) } return formatter, err } diff --git a/v1/init.go b/v1/init.go index c4456a4..fea7c37 100644 --- a/v1/init.go +++ b/v1/init.go @@ -193,6 +193,7 @@ func init() { RegisterFormatFactory(FormatHappy, formatFactory) RegisterFormatFactory(FormatText, formatFactory) RegisterFormatFactory(FormatJSON, formatFactory) + RegisterFormatFactory(FormatRFC5424, formatFactory) ProcessEnv(readFromEnviron()) // package logger for users diff --git a/v1/logger.go b/v1/logger.go index 113a38a..98ac0a2 100644 --- a/v1/logger.go +++ b/v1/logger.go @@ -100,6 +100,8 @@ const FormatText = "text" // FormatJSON uses JSONFormatter const FormatJSON = "JSON" +const FormatRFC5424 = "RFC5424" + // FormatEnv selects formatter based on LOGXI_FORMAT environment variable const FormatEnv = "" diff --git a/v1/rfc5424Formatter.go b/v1/rfc5424Formatter.go new file mode 100644 index 0000000..769e5ea --- /dev/null +++ b/v1/rfc5424Formatter.go @@ -0,0 +1,94 @@ +package log + +import ( + "fmt" + "io" + "os" + "runtime/debug" + "strconv" + "strings" + "time" +) + +// RFC5424Formatter is the default recorder used if one is unspecified when +// creating a new Logger. +type RFC5424Formatter struct { + name string +} + +// NewRFC5424Formatter returns a new instance of RFC5424Formatter. SetName +// must be called befored using it. +func NewRFC5424Formatter(name string) *RFC5424Formatter { + return &RFC5424Formatter{name: name} +} + +func (tf *RFC5424Formatter) set(buf bufferWriter, key string, val interface{}) { + buf.WriteString(" ") + buf.WriteString(key) + buf.WriteString("=") + if err, ok := val.(error); ok { + buf.WriteString(err.Error()) + buf.WriteString(strings.Replace(string(debug.Stack()), "\n", " | ", -1)) + return + } + buf.WriteString(fmt.Sprintf("\"%v\"", val)) +} + +// Format records a log entry. +func (tf *RFC5424Formatter) Format(writer io.Writer, level int, msg string, args []interface{}) { + buf := pool.Get() + defer pool.Put(buf) + + // VERSION TIMESTAMP HOSTNAME APP-NAME PROC-ID MSGID MSG" + + // Prival = Facility + Priority + // Facility is "user", so "1", x 8. Therefore, 8 + // Priority is the same as level, except Emergency is 0 not -1, and there is + // no Trace or All so these are converted to DEBUG + priority := level + if level < 0 { + priority = 0 + } else if level > 7 { + priority = 7 + } + prival := 8 + priority + + buf.WriteString("<" + strconv.Itoa(prival) + ">1 ") + buf.WriteString(time.Now().Format(time.RFC3339)) + buf.WriteString(" ") + hostname, _ := os.Hostname() + buf.WriteString(hostname) + buf.WriteString(" ") + buf.WriteString(tf.name) + buf.WriteString(" ") + buf.WriteString(pidStr) + buf.WriteString(" - ") + + var lenArgs = len(args) + if lenArgs > 0 { + buf.WriteString("[SDID@1") + if lenArgs == 1 { + tf.set(buf, singleArgKey, args[0]) + } else if lenArgs%2 == 0 { + for i := 0; i < lenArgs; i += 2 { + if key, ok := args[i].(string); ok { + if key == "" { + // show key is invalid + tf.set(buf, badKeyAtIndex(i), args[i+1]) + } else { + tf.set(buf, key, args[i+1]) + } + } else { + // show key is invalid + tf.set(buf, badKeyAtIndex(i), args[i+1]) + } + } + } else { + tf.set(buf, warnImbalancedKey, args) + } + buf.WriteString("] ") + } + buf.WriteString(msg) + buf.WriteRune('\n') + buf.WriteTo(writer) +} From 0b209a53a32966a7294f0851829ac6b90f2b2ace Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Thu, 25 Aug 2016 05:53:09 -0400 Subject: [PATCH 7/7] Adds log level (human readable), and some more path changes (mostly in docs) to reflect the clone. --- README.md | 6 +++--- v1/rfc5424Formatter.go | 4 +++- v1/util.go | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c998168..0093174 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -![demo](https://github.com/mgutz/logxi/raw/master/images/demo.gif) +![demo](https://github.com/serussell/logxi/raw/master/images/demo.gif) # logxi @@ -22,12 +22,12 @@ logger built for speed and happy development. ### Installation - go get -u github.com/mgutz/logxi/v1 + go get -u github.com/serussell/logxi/v1 ### Getting Started ```go -import "github.com/mgutz/logxi/v1" +import "github.com/serussell/logxi/v1" // create package variable for Logger interface var logger log.Logger diff --git a/v1/rfc5424Formatter.go b/v1/rfc5424Formatter.go index 769e5ea..136832a 100644 --- a/v1/rfc5424Formatter.go +++ b/v1/rfc5424Formatter.go @@ -62,7 +62,9 @@ func (tf *RFC5424Formatter) Format(writer io.Writer, level int, msg string, args buf.WriteString(tf.name) buf.WriteString(" ") buf.WriteString(pidStr) - buf.WriteString(" - ") + buf.WriteString(" ") + buf.WriteString(LevelMap[level]) + buf.WriteString(" ") var lenArgs = len(args) if lenArgs > 0 { diff --git a/v1/util.go b/v1/util.go index 22f3130..3db1786 100644 --- a/v1/util.go +++ b/v1/util.go @@ -44,7 +44,7 @@ func indexOfNonSpace(s string) int { return -1 } -var inLogxiPath = filepath.Join("mgutz", "logxi", "v"+strings.Split(Version, ".")[0]) +var inLogxiPath = filepath.Join("serussell", "logxi", "v"+strings.Split(Version, ".")[0]) func isLogxiCode(filename string) bool { // need to see errors in tests