diff --git a/fields.go b/fields.go new file mode 100644 index 0000000..c0f2bdc --- /dev/null +++ b/fields.go @@ -0,0 +1,12 @@ +package log + +func (l myLogger) WithFields(fields Fields) Logger { + if l.data != nil && len(l.data) > 0 { + for k, v := range fields { + l.data[k] = v + } + } else { + l.data = fields + } + return l +} diff --git a/logger.go b/logger.go index 254be91..4f69469 100644 --- a/logger.go +++ b/logger.go @@ -29,4 +29,6 @@ type Logger interface { End(a ...interface{}) Level(uint8) Logger + + WithFields(fields Fields) Logger } diff --git a/logger_alert.go b/logger_alert.go index b6ed88a..2411a80 100644 --- a/logger_alert.go +++ b/logger_alert.go @@ -4,12 +4,12 @@ func (l myLogger) Alert(a ...interface{}) { if !hasLevel(l.level, alertFlag) { return } - l.log(a...) + l.log(alertFlag, a...) } func (l myLogger) Alertf(format string, a ...interface{}) { if !hasLevel(l.level, alertFlag) { return } - l.logf(format, a...) + l.logf(alertFlag, format, a...) } diff --git a/logger_begin.go b/logger_begin.go index 54eac56..b9e9c05 100644 --- a/logger_begin.go +++ b/logger_begin.go @@ -4,8 +4,8 @@ import "time" func (l myLogger) Begin(s ...interface{}) Logger { if hasLevel(l.level, logFlag) { - l.log(append([]interface{}{"BEGIN"}, s...)...) + l.log(logFlag, append([]interface{}{"BEGIN"}, s...)...) } - logger := myLogger{Writer: l.Writer, prefix: l.prefix, begin: time.Now(), level: l.level} + logger := myLogger{Writer: l.Writer, ErrWriter: l.ErrWriter, prefix: l.prefix, begin: time.Now(), level: l.level, data: l.data} return logger } diff --git a/logger_end.go b/logger_end.go index e5c8e5a..ddaa46d 100644 --- a/logger_end.go +++ b/logger_end.go @@ -8,6 +8,6 @@ import ( func (l myLogger) End(s ...interface{}) { if hasLevel(l.level, logFlag) { var p []interface{} = append([]interface{}{fmt.Sprintf("END δt=%dµs", time.Now().Sub(l.begin)/1000)}, s...) - l.log(p...) + l.log(logFlag, p...) } } diff --git a/logger_error.go b/logger_error.go index 58c1bf6..60aed6d 100644 --- a/logger_error.go +++ b/logger_error.go @@ -4,12 +4,12 @@ func (l myLogger) Error(a ...interface{}) { if !hasLevel(l.level, errorFlag) { return } - l.log(a...) + l.log(errorFlag, a...) } func (l myLogger) Errorf(format string, a ...interface{}) { if !hasLevel(l.level, errorFlag) { return } - l.logf(format, a...) + l.logf(errorFlag, format, a...) } diff --git a/logger_highlight.go b/logger_highlight.go index b8f5a24..50f2bcd 100644 --- a/logger_highlight.go +++ b/logger_highlight.go @@ -4,12 +4,12 @@ func (l myLogger) Highlight(a ...interface{}) { if !hasLevel(l.level, highlightFlag) { return } - l.log(a...) + l.log(highlightFlag, a...) } func (l myLogger) Highlightf(format string, a ...interface{}) { if !hasLevel(l.level, highlightFlag) { return } - l.logf(format, a...) + l.logf(highlightFlag, format, a...) } diff --git a/logger_inform.go b/logger_inform.go index 1549423..4da3ad5 100644 --- a/logger_inform.go +++ b/logger_inform.go @@ -4,12 +4,12 @@ func (l myLogger) Inform(a ...interface{}) { if !hasLevel(l.level, informFlag) { return } - l.log(a...) + l.log(informFlag, a...) } func (l myLogger) Informf(format string, a ...interface{}) { if !hasLevel(l.level, informFlag) { return } - l.logf(format, a...) + l.logf(informFlag, format, a...) } diff --git a/logger_level.go b/logger_level.go index bc23077..77a8e28 100644 --- a/logger_level.go +++ b/logger_level.go @@ -2,12 +2,12 @@ package log const ( alertFlag = 0b00000001 // L1 - errorFlag = 0b00000001 // L1 - warnFlag = 0b00000010 // L2 - highlightFlag = 0b00000100 // L3 - informFlag = 0b00001000 // L4 - logFlag = 0b00010000 // L5 - traceFlag = 0b00100000 // L6 + errorFlag = 0b00000010 // L2 + warnFlag = 0b00000100 // L3 + highlightFlag = 0b00001000 // L4 + informFlag = 0b00010000 // L5 + logFlag = 0b00100000 // L6 + traceFlag = 0b01000000 // L7 ) // Level returns a leveled logger, level can be from 1 to 6. @@ -20,19 +20,21 @@ const ( // Anything above 6 as level will be considered Level 6. // Pass 0 to output no logs. func (l myLogger) Level(level uint8) Logger { - logger := myLogger{Writer: l.Writer, prefix: l.prefix, begin: l.begin} + logger := myLogger{Writer: l.Writer, ErrWriter: l.ErrWriter, prefix: l.prefix, begin: l.begin, data: l.data} switch level { case 1: - logger.level = alertFlag | errorFlag + logger.level = alertFlag case 2: - logger.level = alertFlag | errorFlag | warnFlag + logger.level = alertFlag | errorFlag case 3: - logger.level = alertFlag | errorFlag | warnFlag | highlightFlag + logger.level = alertFlag | errorFlag | warnFlag case 4: - logger.level = alertFlag | errorFlag | warnFlag | highlightFlag | informFlag + logger.level = alertFlag | errorFlag | warnFlag | highlightFlag case 5: - logger.level = alertFlag | errorFlag | warnFlag | highlightFlag | informFlag | logFlag + logger.level = alertFlag | errorFlag | warnFlag | highlightFlag | informFlag case 6: + logger.level = alertFlag | errorFlag | warnFlag | highlightFlag | informFlag | logFlag + case 7: logger.level = alertFlag | errorFlag | warnFlag | highlightFlag | informFlag | logFlag | traceFlag default: logger.level = 0 @@ -40,6 +42,27 @@ func (l myLogger) Level(level uint8) Logger { return logger } +func unmarshalLevel(level uint8) string { + switch level { + case alertFlag: + return "alert" + case errorFlag: + return "error" + case warnFlag: + return "warn" + case highlightFlag: + return "highlight" + case informFlag: + return "inform" + case logFlag: + return "log" + case traceFlag: + return "trace" + default: + return "" + } +} + func hasLevel(b uint8, flag uint8) bool { return b&flag != 0 } diff --git a/logger_log.go b/logger_log.go index 3794cdb..999a58f 100644 --- a/logger_log.go +++ b/logger_log.go @@ -4,12 +4,12 @@ func (l myLogger) Log(s ...interface{}) { if !hasLevel(l.level, logFlag) { return } - l.log(s...) + l.log(logFlag, s...) } func (l myLogger) Logf(format string, s ...interface{}) { if !hasLevel(l.level, logFlag) { return } - l.logf(format, s...) + l.logf(logFlag, format, s...) } diff --git a/logger_prefix.go b/logger_prefix.go index ef68ee7..e61dcbd 100644 --- a/logger_prefix.go +++ b/logger_prefix.go @@ -11,6 +11,6 @@ func (l myLogger) Prefix(p ...string) Logger { for _, prefix := range p { buffer.WriteString(fmt.Sprintf("%s: ", prefix)) } - logger := myLogger{Writer: l.Writer, prefix: buffer.String()} + logger := myLogger{Writer: l.Writer, ErrWriter: l.ErrWriter, prefix: buffer.String(), data: l.data} return logger } diff --git a/logger_trace.go b/logger_trace.go index c401599..e57aada 100644 --- a/logger_trace.go +++ b/logger_trace.go @@ -4,12 +4,12 @@ func (l myLogger) Trace(a ...interface{}) { if !hasLevel(l.level, traceFlag) { return } - l.log(a...) + l.log(traceFlag, a...) } func (l myLogger) Tracef(format string, a ...interface{}) { if !hasLevel(l.level, traceFlag) { return } - l.logf(format, a...) + l.logf(traceFlag, format, a...) } diff --git a/logger_warn.go b/logger_warn.go index db8b110..e060320 100644 --- a/logger_warn.go +++ b/logger_warn.go @@ -4,12 +4,12 @@ func (l myLogger) Warn(a ...interface{}) { if !hasLevel(l.level, warnFlag) { return } - l.log(a...) + l.log(warnFlag, a...) } func (l myLogger) Warnf(format string, a ...interface{}) { if !hasLevel(l.level, warnFlag) { return } - l.logf(format, a...) + l.logf(warnFlag, format, a...) } diff --git a/my_logger.go b/my_logger.go index 112f0a0..5f2eb06 100644 --- a/my_logger.go +++ b/my_logger.go @@ -9,29 +9,66 @@ import ( "time" ) +var ( + DefaultTimeFormat = time.RFC3339 +) + +type Fields map[string]interface{} + type myLogger struct { - Writer io.Writer - prefix string - begin time.Time - level uint8 + Writer io.Writer + ErrWriter io.Writer + prefix string + begin time.Time + level uint8 + data Fields } -func (l myLogger) log(s ...interface{}) { - if l.Writer == nil { - return - } - s = append([]interface{}{l.prefix, funcName()}, s...) - fmt.Fprintln(l.Writer, s...) +func logPrefix(level uint8) string { + return fmt.Sprintf("time=%q level=%s function=%s", time.Now().Format(DefaultTimeFormat), unmarshalLevel(level), funcName()) } -func (l myLogger) logf(format string, s ...interface{}) { - if l.Writer == nil { - return +func (fields Fields) String() string { + if len(fields) == 0 { + return "" } - format = fmt.Sprintf("%%s %%s %s\n", format) - s = append([]interface{}{l.prefix, funcName()}, s...) + var buffer strings.Builder + for k, v := range fields { + switch v := v.(type) { + case string: + buffer.WriteString(fmt.Sprintf(" %s=%q", k, v)) + default: + buffer.WriteString(fmt.Sprintf(" %s=%v", k, v)) + } + } + return buffer.String() +} - fmt.Fprintf(l.Writer, format, s...) +func (l myLogger) log(flag uint8, s ...interface{}) { + var w io.Writer + { + if flag == errorFlag { + w = l.ErrWriter + } else { + w = l.Writer + } + } + f := fmt.Sprintf("%s%s msg=%q%s", logPrefix(flag), l.prefix, fmt.Sprint(s...), l.data) + fmt.Fprintln(w, f) +} + +func (l myLogger) logf(flag uint8, format string, s ...interface{}) { + var w io.Writer + { + if flag == errorFlag { + w = l.ErrWriter + } else { + w = l.Writer + } + } + format = fmt.Sprintf("%%s%%s msg=\"%s\"%s\n", format, l.data) + s = append([]interface{}{logPrefix(flag), l.prefix}, s...) + fmt.Fprintf(w, format, s...) } func funcName() string { @@ -40,19 +77,28 @@ func funcName() string { for _, p := range pc { fn := runtime.FuncForPC(p) if !strings.HasPrefix(fn.Name(), "github.com/rjbasitali/go-log") { - return fn.Name() + fname := fn.Name() + i := strings.LastIndexByte(fname, byte('/')) + if i == -1 { + return fname + } + return fname[i+1:] } } return "" } -func NewLogger(w io.Writer) Logger { +func NewLogger(w, errw io.Writer) Logger { if w == nil { w = os.Stdout } + if errw == nil { + errw = os.Stderr + } return myLogger{ - Writer: w, - begin: time.Now(), - level: 63, + Writer: w, + ErrWriter: errw, + begin: time.Now(), + level: traceFlag, } }