From f8c068f8771c4ac6fdbb12095fba4b843fb86863 Mon Sep 17 00:00:00 2001 From: Abhay Gupta Date: Tue, 17 Jul 2018 21:14:47 +0530 Subject: [PATCH] Log levels for better coupling and clarity There are over 170 go packages using this log module which simply write the logs with 'Error' as the log level. The existing logging technique works well for terminal but it is not friendly when integrated with other systems. change will produce clearly formatted logs with appropriate log levels. --- log/logger.go | 68 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/log/logger.go b/log/logger.go index ca3e0b0599..6e7587472b 100644 --- a/log/logger.go +++ b/log/logger.go @@ -1,11 +1,15 @@ package log import ( + "bytes" "fmt" "os" + "strings" + "sync/atomic" "time" "github.com/go-stack/stack" + "github.com/golang/glog" ) const timeKey = "t" @@ -131,19 +135,22 @@ type logger struct { } func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) { - l.h.Log(&Record{ - Time: time.Now(), - Lvl: lvl, - Msg: msg, - Ctx: newContext(l.ctx, ctx), - Call: stack.Caller(skip), - KeyNames: RecordKeyNames{ - Time: timeKey, - Msg: msgKey, - Lvl: lvlKey, - Ctx: ctxKey, - }, - }) + switch lvl { + case LvlTrace: + glog.V(3).Info(getLogMsg(msg, newContext(l.ctx, ctx), skip)) + case LvlDebug: + glog.V(2).Info(getLogMsg(msg, newContext(l.ctx, ctx), skip)) + case LvlInfo: + glog.Info(getLogMsg(msg, newContext(l.ctx, ctx), skip)) + case LvlWarn: + glog.Warning(getLogMsg(msg, newContext(l.ctx, ctx), skip)) + case LvlError: + glog.Error(getLogMsg(msg, newContext(l.ctx, ctx), skip)) + case LvlCrit: + glog.Fatal(getLogMsg(msg, newContext(l.ctx, ctx), skip)) + default: + glog.Info(getLogMsg(msg, newContext(l.ctx, ctx), skip)) + } } func (l *logger) New(ctx ...interface{}) Logger { @@ -193,6 +200,41 @@ func (l *logger) SetHandler(h Handler) { l.h.Swap(h) } +// getLogMsg method returns the log message in the following format: +// +func getLogMsg(msg string, ctx []interface{}, skip int) string { + // locationEnabled is an atomic flag controlling whether the formatter should + // append the log locations too when printing entries. + atomic.StoreUint32(&locationEnabled, 0) + // Format the location path and line number. + location := fmt.Sprintf("%+v", stack.Caller(skip)) + align := int(atomic.LoadUint32(&locationLength)) + // Maintain the maximum location length for fancyer alignment. + if align < len(location) { + align = len(location) + atomic.StoreUint32(&locationLength, uint32(align)) + } + // Specifying padding based on the maximum length of the string representing + // the location of the origin of the log. + padding := strings.Repeat(" ", align-len(location)) + buf := &bytes.Buffer{} + buf.WriteString(location) + buf.WriteString(padding) + buf.WriteString(msg) + // Maintain the maximum log message length for fancier alignment. + if align < len(msg) { + align = len(msg) + atomic.StoreUint32(&locationLength, uint32(align)) + } + // Specifying padding based on the maximum length of the string representing + // the logged message. + padding = strings.Repeat(" ", align-len(msg)) + buf.WriteString(padding) + // Writing key-value pairs of the context into the buffer. + logfmt(buf, ctx, 0, false) + return string(buf.Bytes()[:]) +} + func normalize(ctx []interface{}) []interface{} { // if the caller passed a Ctx object, then expand it if len(ctx) == 1 {