From 271246427f8cd012a274a27d15d05939f5bab624 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Date: Sat, 26 Aug 2017 14:19:54 -0300 Subject: [PATCH 01/25] creating context logger --- .gitignore | 2 + contextlogger.go | 136 ++++++++++++++++++++++++++++++++++++++++++ contextlogger_test.go | 31 ++++++++++ logger.go | 20 +++++++ trace.go | 47 +++++++++++++++ 5 files changed, 236 insertions(+) create mode 100644 .gitignore create mode 100644 contextlogger.go create mode 100644 contextlogger_test.go create mode 100644 trace.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c38fa4e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +*.iml diff --git a/contextlogger.go b/contextlogger.go new file mode 100644 index 0000000..afbd742 --- /dev/null +++ b/contextlogger.go @@ -0,0 +1,136 @@ +package logging + +import ( + "context" + "sync/atomic" + "os" + "fmt" + "strings" + "bytes" +) + +type ContextLogger struct { + logger Log + ctx context.Context + id uint64 +} + +func (l ContextLogger) Critical(args ...interface{}) { + l.logger.Critical(getArgs(l, args...)...) +} +func (l ContextLogger) Criticalf(format string, args ...interface{}) { + l.logger.Criticalf(getIdConcat(l, format, -1), args...) +} +func (l ContextLogger) Debug(args ...interface{}) { + l.logger.Debug(getArgs(l, args...)...) +} +func (l ContextLogger) Debugf(format string, args ...interface{}) { + l.logger.Debugf(getIdConcat(l, format, -1), args...) +} +func (l ContextLogger) Error(args ...interface{}) { + l.logger.Error(getArgs(l, args...)...) +} +func (l ContextLogger) Errorf(format string, args ...interface{}) { + l.logger.Errorf(getIdConcat(l, format, -1), args...) +} +func (l ContextLogger) Fatal(args ...interface{}) { + l.logger.Fatal(getArgs(l, args...)...) + os.Exit(1) +} +func (l ContextLogger) Fatalf(format string, args ...interface{}) { + l.logger.Fatalf(getIdConcat(l, format, -1), args...) + os.Exit(1) +} +func (l ContextLogger) Info(args ...interface{}) { + l.logger.Info(getArgs(l, args...)...) +} +func (l ContextLogger) Infof(format string, args ...interface{}) { + l.logger.Infof(getIdConcat(l, format, -1), args...) + +} + +func (l ContextLogger) Notice(args ...interface{}) { + l.logger.Notice(getArgs(l, args...)...) +} +func (l ContextLogger) Noticef(format string, args ...interface{}) { + l.logger.Noticef(getIdConcat(l, format, -1), args...) +} +func (l ContextLogger) Panic(args ...interface{}) { + l.logger.Panic(args) + panic(fmt.Sprint(args...)) +} +func (l ContextLogger) Panicf(format string, args ...interface{}) { + l.logger.Panicf(getIdConcat(l, format, -1), args...) + panic(fmt.Sprintf(format, args...)) +} + +func (l ContextLogger) Warning(args ...interface{}) { + l.logger.Warning(getArgs(l, args...)...) +} +func (l ContextLogger) Warningf(format string, args ...interface{}) { + l.logger.Warningf(getIdConcat(l, format, -1), args...) +} + + +func getArgs(l ContextLogger, args ...interface{}) []interface{} { + var ar []interface{} + ar = append(ar, strings.Trim(getId(l), " ")) + ar = append(ar, args...) + return ar; +} + +func getId(l ContextLogger) string { + return getIdConcat(l, "", 5) +} + +func getIdConcat(l ContextLogger, append string, level int ) string { + if level == -1{ + level = 3 + } + var buffer bytes.Buffer + buffer.WriteString("id=") + buffer.WriteString(fmt.Sprintf("%d, ", l.id)) + buffer.WriteString("m=") + buffer.WriteString(GetCallerFunctionNameSkippingAnnonymous(level)) + buffer.WriteString(" ") + buffer.WriteString(append) + return buffer.String() +} + +func NewLog(logger Log) Log { + + ctx := NewContext() + var ctxLogger ContextLogger + if id := ctx.Value(idKey); id != nil { + ctxLogger = ContextLogger{logger, ctx, id.(uint64)} + } else { + ctxContext := ContextWithId(ctx) + ctxLogger = ContextLogger{logger, ctxContext, ctxContext.Value(id).(uint64)} + } + return ctxLogger +} + +func NewLogWithContext(ctx context.Context, logger Log) Log { + + var ctxLogger ContextLogger + if id := ctx.Value(idKey); id != nil { + ctxLogger = ContextLogger{logger, ctx, id.(uint64)} + } else { + ctxContext := ContextWithId(ctx) + ctxLogger = ContextLogger{logger, ctxContext, ctxContext.Value(id).(uint64)} + } + return &ctxLogger +} + +const idKey = "ctx_id" +var id uint64 = 0; +func NewContext() context.Context { + return ContextWithId(context.Background()) +} + +func ContextWithId(parent context.Context) context.Context { + newId := atomic.AddUint64(&id, 1) + ctx := context.WithValue(parent, idKey, newId) + return ctx +} + diff --git a/contextlogger_test.go b/contextlogger_test.go new file mode 100644 index 0000000..66c00df --- /dev/null +++ b/contextlogger_test.go @@ -0,0 +1,31 @@ +package logging + +import ( + "testing" + "bytes" + "fmt" +) + +func TestNewLog(t *testing.T) { + + buff := bytes.Buffer{} + + logger := MustGetLogger("main") + SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) + SetBackend(NewLogBackend(&buff, "", 0)) + + NewLog(logger).Info("x1") + NewLog(logger).Infof("x2") + + expectedLog := "INF id=1, m=TestNewLog x1\nINF id=2, m=TestNewLog x2\n" + if buff.String() != expectedLog { + t.Fail() + t.Error("current: " + buff.String()) + t.Error("expcted: " + expectedLog) + } + fmt.Println(buff.String()) + +} + + + diff --git a/logger.go b/logger.go index 535ed9b..5428623 100644 --- a/logger.go +++ b/logger.go @@ -88,6 +88,26 @@ func (r *Record) Message() string { return *r.message } + +type Log interface { + Critical(args ...interface{}) + Criticalf(format string, args ...interface{}) + Debug(args ...interface{}) + Debugf(format string, args ...interface{}) + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + Fatal(args ...interface{}) + Fatalf(format string, args ...interface{}) + Info(args ...interface{}) + Infof(format string, args ...interface{}) + Notice(args ...interface{}) + Noticef(format string, args ...interface{}) + Panic(args ...interface{}) + Panicf(format string, args ...interface{}) + Warning(args ...interface{}) + Warningf(format string, args ...interface{}) +} + // Logger is the actual logger which creates log records based on the functions // called and passes them to the underlying logging backend. type Logger struct { diff --git a/trace.go b/trace.go new file mode 100644 index 0000000..a0e43cb --- /dev/null +++ b/trace.go @@ -0,0 +1,47 @@ +package logging + +// returns full package and function name +// 0 for the caller name, 1 for a up level, etc... +import ( + "runtime" + "strings" + "regexp" +) + +func GetCallerName(backLevel int) string { + +pc := make([]uintptr, 10) // at least 1 entry needed +runtime.Callers(backLevel + 2, pc) +f := runtime.FuncForPC(pc[0]) +return f.Name(); + +} + +// returns only function name +func GetCallerFunctionName(backLevel int) string { +caller := GetCallerName(backLevel + 1) +sp := strings.Split(caller, ".") + +if(len(sp) == 0){ +return "" +} + +return sp[len(sp) - 1] +} + + +// retorna o nome da funcao chamadora mas se for uma funcao anonima +// entao busca em um level acima +func GetCallerFunctionNameSkippingAnnonymous(backlevel int) string { + +var name string = ""; +counter :=0 +for tryAgain := true; tryAgain ; counter++ { +name = GetCallerFunctionName(backlevel + 1 + counter) +rx, _ := regexp.Compile("^func\\d+") +tryAgain = rx.MatchString(name) +} + +return name + +} \ No newline at end of file From 4b85d3eb8e194442934af50c9e1961e9592d396c Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Date: Sat, 26 Aug 2017 14:23:56 -0300 Subject: [PATCH 02/25] change to pointer --- contextlogger.go | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/contextlogger.go b/contextlogger.go index afbd742..88213c7 100644 --- a/contextlogger.go +++ b/contextlogger.go @@ -15,77 +15,77 @@ type ContextLogger struct { id uint64 } -func (l ContextLogger) Critical(args ...interface{}) { +func (l *ContextLogger) Critical(args ...interface{}) { l.logger.Critical(getArgs(l, args...)...) } -func (l ContextLogger) Criticalf(format string, args ...interface{}) { +func (l *ContextLogger) Criticalf(format string, args ...interface{}) { l.logger.Criticalf(getIdConcat(l, format, -1), args...) } -func (l ContextLogger) Debug(args ...interface{}) { +func (l *ContextLogger) Debug(args ...interface{}) { l.logger.Debug(getArgs(l, args...)...) } -func (l ContextLogger) Debugf(format string, args ...interface{}) { +func (l *ContextLogger) Debugf(format string, args ...interface{}) { l.logger.Debugf(getIdConcat(l, format, -1), args...) } -func (l ContextLogger) Error(args ...interface{}) { +func (l *ContextLogger) Error(args ...interface{}) { l.logger.Error(getArgs(l, args...)...) } -func (l ContextLogger) Errorf(format string, args ...interface{}) { +func (l *ContextLogger) Errorf(format string, args ...interface{}) { l.logger.Errorf(getIdConcat(l, format, -1), args...) } -func (l ContextLogger) Fatal(args ...interface{}) { +func (l *ContextLogger) Fatal(args ...interface{}) { l.logger.Fatal(getArgs(l, args...)...) os.Exit(1) } -func (l ContextLogger) Fatalf(format string, args ...interface{}) { +func (l *ContextLogger) Fatalf(format string, args ...interface{}) { l.logger.Fatalf(getIdConcat(l, format, -1), args...) os.Exit(1) } -func (l ContextLogger) Info(args ...interface{}) { +func (l *ContextLogger) Info(args ...interface{}) { l.logger.Info(getArgs(l, args...)...) } -func (l ContextLogger) Infof(format string, args ...interface{}) { +func (l *ContextLogger) Infof(format string, args ...interface{}) { l.logger.Infof(getIdConcat(l, format, -1), args...) } -func (l ContextLogger) Notice(args ...interface{}) { +func (l *ContextLogger) Notice(args ...interface{}) { l.logger.Notice(getArgs(l, args...)...) } -func (l ContextLogger) Noticef(format string, args ...interface{}) { +func (l *ContextLogger) Noticef(format string, args ...interface{}) { l.logger.Noticef(getIdConcat(l, format, -1), args...) } -func (l ContextLogger) Panic(args ...interface{}) { +func (l *ContextLogger) Panic(args ...interface{}) { l.logger.Panic(args) panic(fmt.Sprint(args...)) } -func (l ContextLogger) Panicf(format string, args ...interface{}) { +func (l *ContextLogger) Panicf(format string, args ...interface{}) { l.logger.Panicf(getIdConcat(l, format, -1), args...) panic(fmt.Sprintf(format, args...)) } -func (l ContextLogger) Warning(args ...interface{}) { +func (l *ContextLogger) Warning(args ...interface{}) { l.logger.Warning(getArgs(l, args...)...) } -func (l ContextLogger) Warningf(format string, args ...interface{}) { +func (l *ContextLogger) Warningf(format string, args ...interface{}) { l.logger.Warningf(getIdConcat(l, format, -1), args...) } -func getArgs(l ContextLogger, args ...interface{}) []interface{} { +func getArgs(l *ContextLogger, args ...interface{}) []interface{} { var ar []interface{} ar = append(ar, strings.Trim(getId(l), " ")) ar = append(ar, args...) return ar; } -func getId(l ContextLogger) string { - return getIdConcat(l, "", 5) +func getId(l *ContextLogger) string { + return getIdConcat(l, "", 4) } -func getIdConcat(l ContextLogger, append string, level int ) string { +func getIdConcat(l *ContextLogger, append string, level int ) string { if level == -1{ - level = 3 + level = 2 } var buffer bytes.Buffer buffer.WriteString("id=") @@ -107,7 +107,7 @@ func NewLog(logger Log) Log { ctxContext := ContextWithId(ctx) ctxLogger = ContextLogger{logger, ctxContext, ctxContext.Value(id).(uint64)} } - return ctxLogger + return &ctxLogger } func NewLogWithContext(ctx context.Context, logger Log) Log { From 9f46785fd46a427f6ecfee2cb1969a6d1cffe88c Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Date: Sat, 26 Aug 2017 14:40:14 -0300 Subject: [PATCH 03/25] formatting --- trace.go | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/trace.go b/trace.go index a0e43cb..a6c5f59 100644 --- a/trace.go +++ b/trace.go @@ -10,23 +10,23 @@ import ( func GetCallerName(backLevel int) string { -pc := make([]uintptr, 10) // at least 1 entry needed -runtime.Callers(backLevel + 2, pc) -f := runtime.FuncForPC(pc[0]) -return f.Name(); + pc := make([]uintptr, 10) // at least 1 entry needed + runtime.Callers(backLevel + 2, pc) + f := runtime.FuncForPC(pc[0]) + return f.Name(); } // returns only function name func GetCallerFunctionName(backLevel int) string { -caller := GetCallerName(backLevel + 1) -sp := strings.Split(caller, ".") + caller := GetCallerName(backLevel + 1) + sp := strings.Split(caller, ".") -if(len(sp) == 0){ -return "" -} + if (len(sp) == 0) { + return "" + } -return sp[len(sp) - 1] + return sp[len(sp) - 1] } @@ -34,14 +34,14 @@ return sp[len(sp) - 1] // entao busca em um level acima func GetCallerFunctionNameSkippingAnnonymous(backlevel int) string { -var name string = ""; -counter :=0 -for tryAgain := true; tryAgain ; counter++ { -name = GetCallerFunctionName(backlevel + 1 + counter) -rx, _ := regexp.Compile("^func\\d+") -tryAgain = rx.MatchString(name) -} + var name string = ""; + counter := 0 + for tryAgain := true; tryAgain; counter++ { + name = GetCallerFunctionName(backlevel + 1 + counter) + rx, _ := regexp.Compile("^func\\d+") + tryAgain = rx.MatchString(name) + } -return name + return name } \ No newline at end of file From 7a44b89dd8729895685b465e309f2c8253be6a42 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Date: Sat, 26 Aug 2017 18:24:42 -0300 Subject: [PATCH 04/25] MG-364 adding new method to use singleton logger --- contextlogger.go | 10 +++++++++- contextlogger_test.go | 30 +++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/contextlogger.go b/contextlogger.go index 88213c7..2103b13 100644 --- a/contextlogger.go +++ b/contextlogger.go @@ -97,7 +97,15 @@ func getIdConcat(l *ContextLogger, append string, level int ) string { return buffer.String() } -func NewLog(logger Log) Log { +var logger Log; +var instanced int32 = 0 +func NewLog(ctx context.Context) Log { + if(atomic.CompareAndSwapInt32(&instanced, 0, 1)){ + logger = MustGetLogger("main") + } + return NewLogWithContext(ctx, logger) +} +func NewLogWithLogger(logger Log) Log { ctx := NewContext() var ctxLogger ContextLogger diff --git a/contextlogger_test.go b/contextlogger_test.go index 66c00df..c4f3a52 100644 --- a/contextlogger_test.go +++ b/contextlogger_test.go @@ -6,7 +6,7 @@ import ( "fmt" ) -func TestNewLog(t *testing.T) { +func TestNewLogWithLogger(t *testing.T) { buff := bytes.Buffer{} @@ -14,18 +14,38 @@ func TestNewLog(t *testing.T) { SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) SetBackend(NewLogBackend(&buff, "", 0)) - NewLog(logger).Info("x1") - NewLog(logger).Infof("x2") + NewLogWithLogger(logger).Info("x1") + NewLogWithLogger(logger).Infof("x2") - expectedLog := "INF id=1, m=TestNewLog x1\nINF id=2, m=TestNewLog x2\n" + expectedLog := "INF id=1, m=TestNewLogWithLogger x1\nINF id=2, m=TestNewLogWithLogger x2\n" if buff.String() != expectedLog { t.Fail() t.Error("current: " + buff.String()) - t.Error("expcted: " + expectedLog) + t.Error("expected: " + expectedLog) } fmt.Println(buff.String()) } +func TestNewLog(t *testing.T) { + + buff := bytes.Buffer{} + + SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) + SetBackend(NewLogBackend(&buff, "", 0)) + + NewLog(NewContext()).Info("y1") + NewLog(NewContext()).Infof("y2") + + expectedLog := "INF id=3, m=TestNewLog y1\nINF id=4, m=TestNewLog y2\n" + + + if buff.String() != expectedLog { + t.Fail() + t.Error("current: " + buff.String()) + t.Error("expected: " + expectedLog) + } + fmt.Println(buff.String()) +} From c1be5d6ba49402dab7f1f718a2c11699769dc479 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Wed, 18 Oct 2017 11:45:16 -0200 Subject: [PATCH 05/25] simplifying --- contextlogger.go | 135 +++++++---------------------------------------- 1 file changed, 20 insertions(+), 115 deletions(-) diff --git a/contextlogger.go b/contextlogger.go index 2103b13..73555cf 100644 --- a/contextlogger.go +++ b/contextlogger.go @@ -1,144 +1,49 @@ package logging import ( - "context" - "sync/atomic" - "os" - "fmt" - "strings" "bytes" ) -type ContextLogger struct { +type nativeLogger struct { logger Log - ctx context.Context - id uint64 } -func (l *ContextLogger) Critical(args ...interface{}) { - l.logger.Critical(getArgs(l, args...)...) +func (l *nativeLogger) Debug(args ...interface{}) { + l.logger.Debug(withMethod("")...) } -func (l *ContextLogger) Criticalf(format string, args ...interface{}) { - l.logger.Criticalf(getIdConcat(l, format, -1), args...) -} -func (l *ContextLogger) Debug(args ...interface{}) { - l.logger.Debug(getArgs(l, args...)...) -} -func (l *ContextLogger) Debugf(format string, args ...interface{}) { - l.logger.Debugf(getIdConcat(l, format, -1), args...) -} -func (l *ContextLogger) Error(args ...interface{}) { - l.logger.Error(getArgs(l, args...)...) -} -func (l *ContextLogger) Errorf(format string, args ...interface{}) { - l.logger.Errorf(getIdConcat(l, format, -1), args...) -} -func (l *ContextLogger) Fatal(args ...interface{}) { - l.logger.Fatal(getArgs(l, args...)...) - os.Exit(1) -} -func (l *ContextLogger) Fatalf(format string, args ...interface{}) { - l.logger.Fatalf(getIdConcat(l, format, -1), args...) - os.Exit(1) -} -func (l *ContextLogger) Info(args ...interface{}) { - l.logger.Info(getArgs(l, args...)...) -} -func (l *ContextLogger) Infof(format string, args ...interface{}) { - l.logger.Infof(getIdConcat(l, format, -1), args...) +func (l *nativeLogger) Debugf(format string, args ...interface{}) { + l.logger.Debugf(withMethod(format), args...) } -func (l *ContextLogger) Notice(args ...interface{}) { - l.logger.Notice(getArgs(l, args...)...) -} -func (l *ContextLogger) Noticef(format string, args ...interface{}) { - l.logger.Noticef(getIdConcat(l, format, -1), args...) -} -func (l *ContextLogger) Panic(args ...interface{}) { - l.logger.Panic(args) - panic(fmt.Sprint(args...)) +func (l *nativeLogger) Info(args ...interface{}) { + l.logger.Info(withMethod("")...) } -func (l *ContextLogger) Panicf(format string, args ...interface{}) { - l.logger.Panicf(getIdConcat(l, format, -1), args...) - panic(fmt.Sprintf(format, args...)) +func (l *nativeLogger) Infof(format string, args ...interface{}) { + l.logger.Infof(withMethod(format), args...) } -func (l *ContextLogger) Warning(args ...interface{}) { - l.logger.Warning(getArgs(l, args...)...) +func (l *nativeLogger) Warning(args ...interface{}) { + l.logger.Warning(withMethod("")...) } -func (l *ContextLogger) Warningf(format string, args ...interface{}) { - l.logger.Warningf(getIdConcat(l, format, -1), args...) +func (l *nativeLogger) Warningf(format string, args ...interface{}) { + l.logger.Warningf(withMethod(format), args...) } - -func getArgs(l *ContextLogger, args ...interface{}) []interface{} { - var ar []interface{} - ar = append(ar, strings.Trim(getId(l), " ")) - ar = append(ar, args...) - return ar; +func (l *nativeLogger) Error(args ...interface{}) { + l.logger.Error(withMethod("")...) } - -func getId(l *ContextLogger) string { - return getIdConcat(l, "", 4) +func (l *nativeLogger) Errorf(format string, args ...interface{}) { + l.logger.Errorf(withMethod(format), args...) } -func getIdConcat(l *ContextLogger, append string, level int ) string { - if level == -1{ - level = 2 - } + +const level = 2 +func withMethod(append string) string { var buffer bytes.Buffer - buffer.WriteString("id=") - buffer.WriteString(fmt.Sprintf("%d, ", l.id)) buffer.WriteString("m=") buffer.WriteString(GetCallerFunctionNameSkippingAnnonymous(level)) buffer.WriteString(" ") buffer.WriteString(append) return buffer.String() } - -var logger Log; -var instanced int32 = 0 -func NewLog(ctx context.Context) Log { - if(atomic.CompareAndSwapInt32(&instanced, 0, 1)){ - logger = MustGetLogger("main") - } - return NewLogWithContext(ctx, logger) -} -func NewLogWithLogger(logger Log) Log { - - ctx := NewContext() - var ctxLogger ContextLogger - if id := ctx.Value(idKey); id != nil { - ctxLogger = ContextLogger{logger, ctx, id.(uint64)} - } else { - ctxContext := ContextWithId(ctx) - ctxLogger = ContextLogger{logger, ctxContext, ctxContext.Value(id).(uint64)} - } - return &ctxLogger -} - -func NewLogWithContext(ctx context.Context, logger Log) Log { - - var ctxLogger ContextLogger - if id := ctx.Value(idKey); id != nil { - ctxLogger = ContextLogger{logger, ctx, id.(uint64)} - } else { - ctxContext := ContextWithId(ctx) - ctxLogger = ContextLogger{logger, ctxContext, ctxContext.Value(id).(uint64)} - } - return &ctxLogger -} - -const idKey = "ctx_id" -var id uint64 = 0; -func NewContext() context.Context { - return ContextWithId(context.Background()) -} - -func ContextWithId(parent context.Context) context.Context { - newId := atomic.AddUint64(&id, 1) - ctx := context.WithValue(parent, idKey, newId) - return ctx -} - From 876346c94a29f22a31066e253d7ee7470d8c0623 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Wed, 18 Oct 2017 12:11:29 -0200 Subject: [PATCH 06/25] switching to new log structure --- contextlogger.go | 72 +++++++++++++++++++++++++-------- contextlogger_test.go | 93 ++++++++++++++++++++++--------------------- logger.go | 36 ++++++++--------- 3 files changed, 120 insertions(+), 81 deletions(-) diff --git a/contextlogger.go b/contextlogger.go index 73555cf..d591821 100644 --- a/contextlogger.go +++ b/contextlogger.go @@ -2,48 +2,86 @@ package logging import ( "bytes" + "log" + "os" ) +type Printer interface { + Printf(format string, args ... interface{}) +} + +type Log interface { + + Debug(args ...interface{}) + Debugf(format string, args ...interface{}) + + //Info(args ...interface{}) + //Infof(format string, args ...interface{}) + // + //Warning(args ...interface{}) + //Warningf(format string, args ...interface{}) + // + //Error(args ...interface{}) + //Errorf(format string, args ...interface{}) + +} + type nativeLogger struct { - logger Log + writer Printer +} + +type logPrinter struct { + log *log.Logger +} + +func New() Log { + l := &nativeLogger{&logPrinter{log:log.New(os.Stderr, "", log.LstdFlags)}} + return l; +} + +func(p *logPrinter) Printf(format string, args ... interface{}) { + p.log.Printf(format, args) } func (l *nativeLogger) Debug(args ...interface{}) { - l.logger.Debug(withMethod("")...) + l.writer.Printf(withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")).String(), args...) } func (l *nativeLogger) Debugf(format string, args ...interface{}) { - l.logger.Debugf(withMethod(format), args...) + l.writer.Printf(withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")).String(), args...) } func (l *nativeLogger) Info(args ...interface{}) { - l.logger.Info(withMethod("")...) + //l.writer.Printf(withCallerMethod(""), args...) } func (l *nativeLogger) Infof(format string, args ...interface{}) { - l.logger.Infof(withMethod(format), args...) + //l.writer.Printf(withCallerMethod(format), args...) } func (l *nativeLogger) Warning(args ...interface{}) { - l.logger.Warning(withMethod("")...) + //l.writer.Printf(withCallerMethod(""), args...) } func (l *nativeLogger) Warningf(format string, args ...interface{}) { - l.logger.Warningf(withMethod(format), args...) + //l.writer.Printf(withCallerMethod(format), args...) } func (l *nativeLogger) Error(args ...interface{}) { - l.logger.Error(withMethod("")...) + //l.writer.Printf(withCallerMethod(""), args...) } func (l *nativeLogger) Errorf(format string, args ...interface{}) { - l.logger.Errorf(withMethod(format), args...) + //l.writer.Printf(withCallerMethod(format), args...) } - const level = 2 -func withMethod(append string) string { - var buffer bytes.Buffer - buffer.WriteString("m=") - buffer.WriteString(GetCallerFunctionNameSkippingAnnonymous(level)) - buffer.WriteString(" ") - buffer.WriteString(append) - return buffer.String() +func withCallerMethod(buff *bytes.Buffer) *bytes.Buffer { + buff.WriteString("m=") + buff.WriteString(GetCallerFunctionNameSkippingAnnonymous(level)) + buff.WriteString(" ") + return buff; +} + +func withLevel(buff *bytes.Buffer, lvl string) *bytes.Buffer { + buff.WriteString(lvl) + buff.WriteString(" ") + return buff; } diff --git a/contextlogger_test.go b/contextlogger_test.go index c4f3a52..c26a7af 100644 --- a/contextlogger_test.go +++ b/contextlogger_test.go @@ -1,51 +1,52 @@ package logging -import ( - "testing" - "bytes" - "fmt" -) +import "testing" -func TestNewLogWithLogger(t *testing.T) { - - buff := bytes.Buffer{} - - logger := MustGetLogger("main") - SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) - SetBackend(NewLogBackend(&buff, "", 0)) - - NewLogWithLogger(logger).Info("x1") - NewLogWithLogger(logger).Infof("x2") - - expectedLog := "INF id=1, m=TestNewLogWithLogger x1\nINF id=2, m=TestNewLogWithLogger x2\n" - if buff.String() != expectedLog { - t.Fail() - t.Error("current: " + buff.String()) - t.Error("expected: " + expectedLog) - } - fmt.Println(buff.String()) - -} - -func TestNewLog(t *testing.T) { - - buff := bytes.Buffer{} - - SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) - SetBackend(NewLogBackend(&buff, "", 0)) - - NewLog(NewContext()).Info("y1") - NewLog(NewContext()).Infof("y2") - - expectedLog := "INF id=3, m=TestNewLog y1\nINF id=4, m=TestNewLog y2\n" - - - if buff.String() != expectedLog { - t.Fail() - t.Error("current: " + buff.String()) - t.Error("expected: " + expectedLog) - } - fmt.Println(buff.String()) +func TestDebug(t *testing.T){ + logger := New() + logger.Debugf("name=%s", "elvis"); } - +//func TestNewLogWithLogger(t *testing.T) { +// +// buff := bytes.Buffer{} +// +// logger := MustGetLogger("main") +// SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) +// SetBackend(NewLogBackend(&buff, "", 0)) +// +// NewLogWithLogger(logger).Info("x1") +// NewLogWithLogger(logger).Infof("x2") +// +// expectedLog := "INF id=1, m=TestNewLogWithLogger x1\nINF id=2, m=TestNewLogWithLogger x2\n" +// if buff.String() != expectedLog { +// t.Fail() +// t.Error("current: " + buff.String()) +// t.Error("expected: " + expectedLog) +// } +// fmt.Println(buff.String()) +// +//} +// +//func TestNewLog(t *testing.T) { +// +// buff := bytes.Buffer{} +// +// SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) +// SetBackend(NewLogBackend(&buff, "", 0)) +// +// NewLog(NewContext()).Info("y1") +// NewLog(NewContext()).Infof("y2") +// +// expectedLog := "INF id=3, m=TestNewLog y1\nINF id=4, m=TestNewLog y2\n" +// +// +// if buff.String() != expectedLog { +// t.Fail() +// t.Error("current: " + buff.String()) +// t.Error("expected: " + expectedLog) +// } +// fmt.Println(buff.String()) +//} +// +// diff --git a/logger.go b/logger.go index 5428623..eb375a7 100644 --- a/logger.go +++ b/logger.go @@ -89,24 +89,24 @@ func (r *Record) Message() string { } -type Log interface { - Critical(args ...interface{}) - Criticalf(format string, args ...interface{}) - Debug(args ...interface{}) - Debugf(format string, args ...interface{}) - Error(args ...interface{}) - Errorf(format string, args ...interface{}) - Fatal(args ...interface{}) - Fatalf(format string, args ...interface{}) - Info(args ...interface{}) - Infof(format string, args ...interface{}) - Notice(args ...interface{}) - Noticef(format string, args ...interface{}) - Panic(args ...interface{}) - Panicf(format string, args ...interface{}) - Warning(args ...interface{}) - Warningf(format string, args ...interface{}) -} +//type Log interface { +// Critical(args ...interface{}) +// Criticalf(format string, args ...interface{}) +// Debug(args ...interface{}) +// Debugf(format string, args ...interface{}) +// Error(args ...interface{}) +// Errorf(format string, args ...interface{}) +// Fatal(args ...interface{}) +// Fatalf(format string, args ...interface{}) +// Info(args ...interface{}) +// Infof(format string, args ...interface{}) +// Notice(args ...interface{}) +// Noticef(format string, args ...interface{}) +// Panic(args ...interface{}) +// Panicf(format string, args ...interface{}) +// Warning(args ...interface{}) +// Warningf(format string, args ...interface{}) +//} // Logger is the actual logger which creates log records based on the functions // called and passes them to the underlying logging backend. From e6c75c7821f64ea4c0ccba415ad938528bfaaf8c Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Wed, 18 Oct 2017 19:58:51 -0200 Subject: [PATCH 07/25] adding log level to message and caller method, using default go log as impl --- contextlogger.go | 21 +++++++++++++++------ contextlogger_test.go | 19 +++++++++++++++---- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/contextlogger.go b/contextlogger.go index d591821..4e6dace 100644 --- a/contextlogger.go +++ b/contextlogger.go @@ -3,7 +3,7 @@ package logging import ( "bytes" "log" - "os" + "io" ) type Printer interface { @@ -34,13 +34,13 @@ type logPrinter struct { log *log.Logger } -func New() Log { - l := &nativeLogger{&logPrinter{log:log.New(os.Stderr, "", log.LstdFlags)}} +func New(out io.Writer, prefix string, flag int) Log { + l := &nativeLogger{&logPrinter{log:log.New(out, prefix, flag)}} return l; } -func(p *logPrinter) Printf(format string, args ... interface{}) { - p.log.Printf(format, args) +func(p *logPrinter) Printf(format string, args ...interface{}) { + p.log.Printf(format, args...) } func (l *nativeLogger) Debug(args ...interface{}) { @@ -48,7 +48,7 @@ func (l *nativeLogger) Debug(args ...interface{}) { } func (l *nativeLogger) Debugf(format string, args ...interface{}) { - l.writer.Printf(withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")).String(), args...) + l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")), format).String(), args...) } func (l *nativeLogger) Info(args ...interface{}) { @@ -73,6 +73,8 @@ func (l *nativeLogger) Errorf(format string, args ...interface{}) { } const level = 2 + +// add method caller name to message func withCallerMethod(buff *bytes.Buffer) *bytes.Buffer { buff.WriteString("m=") buff.WriteString(GetCallerFunctionNameSkippingAnnonymous(level)) @@ -80,8 +82,15 @@ func withCallerMethod(buff *bytes.Buffer) *bytes.Buffer { return buff; } +// adding level to message func withLevel(buff *bytes.Buffer, lvl string) *bytes.Buffer { buff.WriteString(lvl) buff.WriteString(" ") return buff; } + +// adding format string to message +func withFormat(buff *bytes.Buffer, format string) *bytes.Buffer { + buff.WriteString(format) + return buff +} \ No newline at end of file diff --git a/contextlogger_test.go b/contextlogger_test.go index c26a7af..12e74ac 100644 --- a/contextlogger_test.go +++ b/contextlogger_test.go @@ -1,10 +1,21 @@ package logging -import "testing" +import ( + "testing" + "log" + "bytes" +) -func TestDebug(t *testing.T){ - logger := New() - logger.Debugf("name=%s", "elvis"); +func TestDebugf(t *testing.T){ + + buff := new(bytes.Buffer) + logger := New(buff, "", log.LstdFlags) + logger.Debugf("name=%v", "elvis"); + + actual := buff.String()[20:] + if actual != "DEBUG m=TestDebugf name=elvis\n" { + t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + } } //func TestNewLogWithLogger(t *testing.T) { From f685f98dadd1cff89d2ec5cc579f170a478b7ad5 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Wed, 18 Oct 2017 20:04:32 -0200 Subject: [PATCH 08/25] adding validations --- contextlogger_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contextlogger_test.go b/contextlogger_test.go index 12e74ac..99d6c60 100644 --- a/contextlogger_test.go +++ b/contextlogger_test.go @@ -8,12 +8,16 @@ import ( func TestDebugf(t *testing.T){ + minSize := 20 + buff := new(bytes.Buffer) logger := New(buff, "", log.LstdFlags) logger.Debugf("name=%v", "elvis"); - actual := buff.String()[20:] - if actual != "DEBUG m=TestDebugf name=elvis\n" { + if buff.Len() < minSize { + t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) + } + if actual := buff.String()[minSize:]; actual != "DEBUG m=TestDebugf name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } From 35c8c76cc17a6a574cf84bf6374f97bc5d2ada11 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 18:02:00 -0200 Subject: [PATCH 09/25] adding and testing others log level methods --- contextlogger.go | 43 +++++++++------- contextlogger_test.go | 113 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 17 deletions(-) diff --git a/contextlogger.go b/contextlogger.go index 4e6dace..0e35a96 100644 --- a/contextlogger.go +++ b/contextlogger.go @@ -7,7 +7,8 @@ import ( ) type Printer interface { - Printf(format string, args ... interface{}) + Printf(format string, args ...interface{}) + Print(args ...interface{}) } type Log interface { @@ -15,14 +16,14 @@ type Log interface { Debug(args ...interface{}) Debugf(format string, args ...interface{}) - //Info(args ...interface{}) - //Infof(format string, args ...interface{}) - // - //Warning(args ...interface{}) - //Warningf(format string, args ...interface{}) - // - //Error(args ...interface{}) - //Errorf(format string, args ...interface{}) + Info(args ...interface{}) + Infof(format string, args ...interface{}) + + Warning(args ...interface{}) + Warningf(format string, args ...interface{}) + + Error(args ...interface{}) + Errorf(format string, args ...interface{}) } @@ -36,15 +37,20 @@ type logPrinter struct { func New(out io.Writer, prefix string, flag int) Log { l := &nativeLogger{&logPrinter{log:log.New(out, prefix, flag)}} - return l; + return l; } func(p *logPrinter) Printf(format string, args ...interface{}) { p.log.Printf(format, args...) } +func(p *logPrinter) Print(args ...interface{}) { + p.log.Print(args...) +} + func (l *nativeLogger) Debug(args ...interface{}) { - l.writer.Printf(withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")).String(), args...) + args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")).String()}, args...) + l.writer.Print(args...) } func (l *nativeLogger) Debugf(format string, args ...interface{}) { @@ -52,24 +58,27 @@ func (l *nativeLogger) Debugf(format string, args ...interface{}) { } func (l *nativeLogger) Info(args ...interface{}) { - //l.writer.Printf(withCallerMethod(""), args...) + args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "INFO")).String()}, args...) + l.writer.Print(args...) } func (l *nativeLogger) Infof(format string, args ...interface{}) { - //l.writer.Printf(withCallerMethod(format), args...) + l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "INFO")), format).String(), args...) } func (l *nativeLogger) Warning(args ...interface{}) { - //l.writer.Printf(withCallerMethod(""), args...) + args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "WARNING")).String()}, args...) + l.writer.Print(args...) } func (l *nativeLogger) Warningf(format string, args ...interface{}) { - //l.writer.Printf(withCallerMethod(format), args...) + l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "WARNING")), format).String(), args...) } func (l *nativeLogger) Error(args ...interface{}) { - //l.writer.Printf(withCallerMethod(""), args...) + args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "ERROR")).String()}, args...) + l.writer.Print(args...) } func (l *nativeLogger) Errorf(format string, args ...interface{}) { - //l.writer.Printf(withCallerMethod(format), args...) + l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "ERROR")), format).String(), args...) } const level = 2 diff --git a/contextlogger_test.go b/contextlogger_test.go index 99d6c60..7b09e6d 100644 --- a/contextlogger_test.go +++ b/contextlogger_test.go @@ -6,6 +6,22 @@ import ( "bytes" ) +func TestDebug(t *testing.T){ + + minSize := 20 + + buff := new(bytes.Buffer) + logger := New(buff, "", log.LstdFlags) + logger.Debug("name=", "elvis"); + + if buff.Len() < minSize { + t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) + } + if actual := buff.String()[minSize:]; actual != "DEBUG m=TestDebug name=elvis\n" { + t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + } +} + func TestDebugf(t *testing.T){ minSize := 20 @@ -22,6 +38,103 @@ func TestDebugf(t *testing.T){ } } +func TestInfo(t *testing.T){ + + minSize := 20 + + buff := new(bytes.Buffer) + logger := New(buff, "", log.LstdFlags) + logger.Info("name=", "elvis"); + + if buff.Len() < minSize { + t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) + } + if actual := buff.String()[minSize:]; actual != "INFO m=TestInfo name=elvis\n" { + t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + } +} + +func TestInfof(t *testing.T){ + + minSize := 20 + + buff := new(bytes.Buffer) + logger := New(buff, "", log.LstdFlags) + logger.Infof("name=%v", "elvis"); + + if buff.Len() < minSize { + t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) + } + if actual := buff.String()[minSize:]; actual != "INFO m=TestInfof name=elvis\n" { + t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + } +} + +func TestWarn(t *testing.T){ + + minSize := 20 + + buff := new(bytes.Buffer) + logger := New(buff, "", log.LstdFlags) + logger.Warning("name=", "elvis"); + + if buff.Len() < minSize { + t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) + } + if actual := buff.String()[minSize:]; actual != "WARNING m=TestWarn name=elvis\n" { + t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + } +} + +func TestWarnf(t *testing.T){ + + minSize := 20 + + buff := new(bytes.Buffer) + logger := New(buff, "", log.LstdFlags) + logger.Warningf("name=%v", "elvis"); + + if buff.Len() < minSize { + t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) + } + if actual := buff.String()[minSize:]; actual != "WARNING m=TestWarnf name=elvis\n" { + t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + } +} + +func TestError(t *testing.T){ + + minSize := 20 + + buff := new(bytes.Buffer) + logger := New(buff, "", log.LstdFlags) + logger.Error("name=", "elvis"); + + if buff.Len() < minSize { + t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) + } + if actual := buff.String()[minSize:]; actual != "ERROR m=TestError name=elvis\n" { + t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + } +} + +func TestErrorf(t *testing.T){ + + minSize := 20 + + buff := new(bytes.Buffer) + logger := New(buff, "", log.LstdFlags) + logger.Errorf("name=%v", "elvis"); + + if buff.Len() < minSize { + t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) + } + if actual := buff.String()[minSize:]; actual != "ERROR m=TestErrorf name=elvis\n" { + t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + } +} + + //func TestNewLogWithLogger(t *testing.T) { // // buff := bytes.Buffer{} From dc110992e930420907b77c9ab039daf29ee48f88 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 18:05:29 -0200 Subject: [PATCH 10/25] simplify tests --- contextlogger_test.go | 118 ++++++------------------------------------ 1 file changed, 16 insertions(+), 102 deletions(-) diff --git a/contextlogger_test.go b/contextlogger_test.go index 7b09e6d..ccb8d17 100644 --- a/contextlogger_test.go +++ b/contextlogger_test.go @@ -2,179 +2,93 @@ package logging import ( "testing" - "log" "bytes" ) func TestDebug(t *testing.T){ - minSize := 20 - buff := new(bytes.Buffer) - logger := New(buff, "", log.LstdFlags) + logger := New(buff, "", 0) logger.Debug("name=", "elvis"); - if buff.Len() < minSize { - t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) - } - if actual := buff.String()[minSize:]; actual != "DEBUG m=TestDebug name=elvis\n" { + if actual := buff.String(); actual != "DEBUG m=TestDebug name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } func TestDebugf(t *testing.T){ - minSize := 20 - buff := new(bytes.Buffer) - logger := New(buff, "", log.LstdFlags) + logger := New(buff, "", 0) logger.Debugf("name=%v", "elvis"); - if buff.Len() < minSize { - t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) - } - if actual := buff.String()[minSize:]; actual != "DEBUG m=TestDebugf name=elvis\n" { + if actual := buff.String(); actual != "DEBUG m=TestDebugf name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } func TestInfo(t *testing.T){ - minSize := 20 - buff := new(bytes.Buffer) - logger := New(buff, "", log.LstdFlags) + logger := New(buff, "", 0) logger.Info("name=", "elvis"); - if buff.Len() < minSize { - t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) - } - if actual := buff.String()[minSize:]; actual != "INFO m=TestInfo name=elvis\n" { + if actual := buff.String(); actual != "INFO m=TestInfo name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } func TestInfof(t *testing.T){ - minSize := 20 - buff := new(bytes.Buffer) - logger := New(buff, "", log.LstdFlags) + logger := New(buff, "", 0) logger.Infof("name=%v", "elvis"); - if buff.Len() < minSize { - t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) - } - if actual := buff.String()[minSize:]; actual != "INFO m=TestInfof name=elvis\n" { + if actual := buff.String(); actual != "INFO m=TestInfof name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } func TestWarn(t *testing.T){ - minSize := 20 - buff := new(bytes.Buffer) - logger := New(buff, "", log.LstdFlags) + logger := New(buff, "", 0) logger.Warning("name=", "elvis"); - if buff.Len() < minSize { - t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) - } - if actual := buff.String()[minSize:]; actual != "WARNING m=TestWarn name=elvis\n" { + if actual := buff.String(); actual != "WARNING m=TestWarn name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } func TestWarnf(t *testing.T){ - minSize := 20 - buff := new(bytes.Buffer) - logger := New(buff, "", log.LstdFlags) + logger := New(buff, "", 0) logger.Warningf("name=%v", "elvis"); - if buff.Len() < minSize { - t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) - } - if actual := buff.String()[minSize:]; actual != "WARNING m=TestWarnf name=elvis\n" { + if actual := buff.String(); actual != "WARNING m=TestWarnf name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } func TestError(t *testing.T){ - minSize := 20 - buff := new(bytes.Buffer) - logger := New(buff, "", log.LstdFlags) + logger := New(buff, "", 0) logger.Error("name=", "elvis"); - if buff.Len() < minSize { - t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) - } - if actual := buff.String()[minSize:]; actual != "ERROR m=TestError name=elvis\n" { + if actual := buff.String(); actual != "ERROR m=TestError name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } func TestErrorf(t *testing.T){ - minSize := 20 - buff := new(bytes.Buffer) - logger := New(buff, "", log.LstdFlags) + logger := New(buff, "", 0) logger.Errorf("name=%v", "elvis"); - if buff.Len() < minSize { - t.Errorf("log must have %d at least, actual=%s", minSize, buff.String()) - } - if actual := buff.String()[minSize:]; actual != "ERROR m=TestErrorf name=elvis\n" { + if actual := buff.String(); actual != "ERROR m=TestErrorf name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } - - -//func TestNewLogWithLogger(t *testing.T) { -// -// buff := bytes.Buffer{} -// -// logger := MustGetLogger("main") -// SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) -// SetBackend(NewLogBackend(&buff, "", 0)) -// -// NewLogWithLogger(logger).Info("x1") -// NewLogWithLogger(logger).Infof("x2") -// -// expectedLog := "INF id=1, m=TestNewLogWithLogger x1\nINF id=2, m=TestNewLogWithLogger x2\n" -// if buff.String() != expectedLog { -// t.Fail() -// t.Error("current: " + buff.String()) -// t.Error("expected: " + expectedLog) -// } -// fmt.Println(buff.String()) -// -//} -// -//func TestNewLog(t *testing.T) { -// -// buff := bytes.Buffer{} -// -// SetFormatter(MustStringFormatter(`%{level:.3s} %{message}`)) -// SetBackend(NewLogBackend(&buff, "", 0)) -// -// NewLog(NewContext()).Info("y1") -// NewLog(NewContext()).Infof("y2") -// -// expectedLog := "INF id=3, m=TestNewLog y1\nINF id=4, m=TestNewLog y2\n" -// -// -// if buff.String() != expectedLog { -// t.Fail() -// t.Error("current: " + buff.String()) -// t.Error("expected: " + expectedLog) -// } -// fmt.Println(buff.String()) -//} -// -// From 607be6b84f437c8761aa10cd31d9814d2b5c68c2 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 18:16:38 -0200 Subject: [PATCH 11/25] refactoring --- .travis.yml | 6 - CHANGELOG.md | 19 -- CONTRIBUTORS | 5 - LICENSE | 27 -- README.md | 93 ----- backend.go | 39 --- example_test.go | 40 --- examples/example.go | 49 --- examples/example.png | Bin 17675 -> 0 bytes format.go | 414 ----------------------- format_test.go | 184 ---------- level.go | 128 ------- level_test.go | 76 ----- log_nix.go | 109 ------ log_test.go | 163 --------- log_windows.go | 107 ------ logger.go | 279 --------------- logger_test.go | 62 ---- logging.go | 28 ++ contextlogger_test.go => logging_test.go | 0 logprinter.go | 25 ++ memory.go | 237 ------------- memory_test.go | 117 ------- multi.go | 65 ---- multi_test.go | 51 --- contextlogger.go => nativelogger.go | 40 +-- syslog.go | 53 --- syslog_fallback.go | 28 -- 28 files changed, 56 insertions(+), 2388 deletions(-) delete mode 100644 .travis.yml delete mode 100644 CHANGELOG.md delete mode 100644 CONTRIBUTORS delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 backend.go delete mode 100644 example_test.go delete mode 100644 examples/example.go delete mode 100644 examples/example.png delete mode 100644 format.go delete mode 100644 format_test.go delete mode 100644 level.go delete mode 100644 level_test.go delete mode 100644 log_nix.go delete mode 100644 log_test.go delete mode 100644 log_windows.go delete mode 100644 logger.go delete mode 100644 logger_test.go create mode 100644 logging.go rename contextlogger_test.go => logging_test.go (100%) create mode 100644 logprinter.go delete mode 100644 memory.go delete mode 100644 memory_test.go delete mode 100644 multi.go delete mode 100644 multi_test.go rename contextlogger.go => nativelogger.go (74%) delete mode 100644 syslog.go delete mode 100644 syslog_fallback.go diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 70e012b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: go - -go: - - 1.0 - - 1.1 - - tip diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 4b7d233..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,19 +0,0 @@ -# Changelog - -## 2.0.0-rc1 (2016-02-11) - -Time flies and it has been three years since this package was first released. -There have been a couple of API changes I have wanted to do for some time but -I've tried to maintain backwards compatibility. Some inconsistencies in the -API have started to show, proper vendor support in Go out of the box and -the fact that `go vet` will give warnings -- I have decided to bump the major -version. - -* Make eg. `Info` and `Infof` do different things. You want to change all calls - to `Info` with a string format go to `Infof` etc. In many cases, `go vet` will - guide you. -* `Id` in `Record` is now called `ID` - -## 1.0.0 (2013-02-21) - -Initial release diff --git a/CONTRIBUTORS b/CONTRIBUTORS deleted file mode 100644 index 958416e..0000000 --- a/CONTRIBUTORS +++ /dev/null @@ -1,5 +0,0 @@ -Alec Thomas -Guilhem Lettron -Ivan Daniluk -Nimi Wariboko Jr -Róbert Selvek diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f1f6cfc..0000000 --- a/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013 Örjan Persson. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md deleted file mode 100644 index 0a7326b..0000000 --- a/README.md +++ /dev/null @@ -1,93 +0,0 @@ -## Golang logging library - -[![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/op/go-logging) [![build](https://img.shields.io/travis/op/go-logging.svg?style=flat)](https://travis-ci.org/op/go-logging) - -Package logging implements a logging infrastructure for Go. Its output format -is customizable and supports different logging backends like syslog, file and -memory. Multiple backends can be utilized with different log levels per backend -and logger. - -**_NOTE:_** backwards compatibility promise have been dropped for master. Please -vendor this package or use `gopkg.in/op/go-logging.v1` for previous version. See -[changelog](CHANGELOG.md) for details. - -## Example - -Let's have a look at an [example](examples/example.go) which demonstrates most -of the features found in this library. - -[![Example Output](examples/example.png)](examples/example.go) - -```go -package main - -import ( - "os" - - "github.com/op/go-logging" -) - -var log = logging.MustGetLogger("example") - -// Example format string. Everything except the message has a custom color -// which is dependent on the log level. Many fields have a custom output -// formatting too, eg. the time returns the hour down to the milli second. -var format = logging.MustStringFormatter( - `%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}`, -) - -// Password is just an example type implementing the Redactor interface. Any -// time this is logged, the Redacted() function will be called. -type Password string - -func (p Password) Redacted() interface{} { - return logging.Redact(string(p)) -} - -func main() { - // For demo purposes, create two backend for os.Stderr. - backend1 := logging.NewLogBackend(os.Stderr, "", 0) - backend2 := logging.NewLogBackend(os.Stderr, "", 0) - - // For messages written to backend2 we want to add some additional - // information to the output, including the used log level and the name of - // the function. - backend2Formatter := logging.NewBackendFormatter(backend2, format) - - // Only errors and more severe messages should be sent to backend1 - backend1Leveled := logging.AddModuleLevel(backend1) - backend1Leveled.SetLevel(logging.ERROR, "") - - // Set the backends to be used. - logging.SetBackend(backend1Leveled, backend2Formatter) - - log.Debugf("debug %s", Password("secret")) - log.Info("info") - log.Notice("notice") - log.Warning("warning") - log.Error("err") - log.Critical("crit") -} -``` - -## Installing - -### Using *go get* - - $ go get github.com/op/go-logging - -After this command *go-logging* is ready to use. Its source will be in: - - $GOPATH/src/pkg/github.com/op/go-logging - -You can use `go get -u` to update the package. - -## Documentation - -For docs, see http://godoc.org/github.com/op/go-logging or run: - - $ godoc github.com/op/go-logging - -## Additional resources - -* [wslog](https://godoc.org/github.com/cryptix/exp/wslog) -- exposes log messages through a WebSocket. diff --git a/backend.go b/backend.go deleted file mode 100644 index 74d9201..0000000 --- a/backend.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -// defaultBackend is the backend used for all logging calls. -var defaultBackend LeveledBackend - -// Backend is the interface which a log backend need to implement to be able to -// be used as a logging backend. -type Backend interface { - Log(Level, int, *Record) error -} - -// SetBackend replaces the backend currently set with the given new logging -// backend. -func SetBackend(backends ...Backend) LeveledBackend { - var backend Backend - if len(backends) == 1 { - backend = backends[0] - } else { - backend = MultiLogger(backends...) - } - - defaultBackend = AddModuleLevel(backend) - return defaultBackend -} - -// SetLevel sets the logging level for the specified module. The module -// corresponds to the string specified in GetLogger. -func SetLevel(level Level, module string) { - defaultBackend.SetLevel(level, module) -} - -// GetLevel returns the logging level for the specified module. -func GetLevel(module string) Level { - return defaultBackend.GetLevel(module) -} diff --git a/example_test.go b/example_test.go deleted file mode 100644 index 52fd733..0000000 --- a/example_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package logging - -import "os" - -func Example() { - // This call is for testing purposes and will set the time to unix epoch. - InitForTesting(DEBUG) - - var log = MustGetLogger("example") - - // For demo purposes, create two backend for os.Stdout. - // - // os.Stderr should most likely be used in the real world but then the - // "Output:" check in this example would not work. - backend1 := NewLogBackend(os.Stdout, "", 0) - backend2 := NewLogBackend(os.Stdout, "", 0) - - // For messages written to backend2 we want to add some additional - // information to the output, including the used log level and the name of - // the function. - var format = MustStringFormatter( - `%{time:15:04:05.000} %{shortfunc} %{level:.1s} %{message}`, - ) - backend2Formatter := NewBackendFormatter(backend2, format) - - // Only errors and more severe messages should be sent to backend2 - backend2Leveled := AddModuleLevel(backend2Formatter) - backend2Leveled.SetLevel(ERROR, "") - - // Set the backends to be used and the default level. - SetBackend(backend1, backend2Leveled) - - log.Debugf("debug %s", "arg") - log.Error("error") - - // Output: - // debug arg - // error - // 00:00:00.000 Example E error -} diff --git a/examples/example.go b/examples/example.go deleted file mode 100644 index 9f4ddee..0000000 --- a/examples/example.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "os" - - "github.com/op/go-logging" -) - -var log = logging.MustGetLogger("example") - -// Example format string. Everything except the message has a custom color -// which is dependent on the log level. Many fields have a custom output -// formatting too, eg. the time returns the hour down to the milli second. -var format = logging.MustStringFormatter( - `%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}`, -) - -// Password is just an example type implementing the Redactor interface. Any -// time this is logged, the Redacted() function will be called. -type Password string - -func (p Password) Redacted() interface{} { - return logging.Redact(string(p)) -} - -func main() { - // For demo purposes, create two backend for os.Stderr. - backend1 := logging.NewLogBackend(os.Stderr, "", 0) - backend2 := logging.NewLogBackend(os.Stderr, "", 0) - - // For messages written to backend2 we want to add some additional - // information to the output, including the used log level and the name of - // the function. - backend2Formatter := logging.NewBackendFormatter(backend2, format) - - // Only errors and more severe messages should be sent to backend1 - backend1Leveled := logging.AddModuleLevel(backend1) - backend1Leveled.SetLevel(logging.ERROR, "") - - // Set the backends to be used. - logging.SetBackend(backend1Leveled, backend2Formatter) - - log.Debugf("debug %s", Password("secret")) - log.Info("info") - log.Notice("notice") - log.Warning("warning") - log.Error("err") - log.Critical("crit") -} diff --git a/examples/example.png b/examples/example.png deleted file mode 100644 index ff3392b7a5b37a09d44db6a8f5ef293c5c610791..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17675 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 diff --git a/format.go b/format.go deleted file mode 100644 index 7160674..0000000 --- a/format.go +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import ( - "bytes" - "errors" - "fmt" - "io" - "os" - "path" - "path/filepath" - "regexp" - "runtime" - "strconv" - "strings" - "sync" - "time" -) - -// TODO see Formatter interface in fmt/print.go -// TODO try text/template, maybe it have enough performance -// TODO other template systems? -// TODO make it possible to specify formats per backend? -type fmtVerb int - -const ( - fmtVerbTime fmtVerb = iota - fmtVerbLevel - fmtVerbID - fmtVerbPid - fmtVerbProgram - fmtVerbModule - fmtVerbMessage - fmtVerbLongfile - fmtVerbShortfile - fmtVerbLongpkg - fmtVerbShortpkg - fmtVerbLongfunc - fmtVerbShortfunc - fmtVerbCallpath - fmtVerbLevelColor - - // Keep last, there are no match for these below. - fmtVerbUnknown - fmtVerbStatic -) - -var fmtVerbs = []string{ - "time", - "level", - "id", - "pid", - "program", - "module", - "message", - "longfile", - "shortfile", - "longpkg", - "shortpkg", - "longfunc", - "shortfunc", - "callpath", - "color", -} - -const rfc3339Milli = "2006-01-02T15:04:05.999Z07:00" - -var defaultVerbsLayout = []string{ - rfc3339Milli, - "s", - "d", - "d", - "s", - "s", - "s", - "s", - "s", - "s", - "s", - "s", - "s", - "0", - "", -} - -var ( - pid = os.Getpid() - program = filepath.Base(os.Args[0]) -) - -func getFmtVerbByName(name string) fmtVerb { - for i, verb := range fmtVerbs { - if name == verb { - return fmtVerb(i) - } - } - return fmtVerbUnknown -} - -// Formatter is the required interface for a custom log record formatter. -type Formatter interface { - Format(calldepth int, r *Record, w io.Writer) error -} - -// formatter is used by all backends unless otherwise overriden. -var formatter struct { - sync.RWMutex - def Formatter -} - -func getFormatter() Formatter { - formatter.RLock() - defer formatter.RUnlock() - return formatter.def -} - -var ( - // DefaultFormatter is the default formatter used and is only the message. - DefaultFormatter = MustStringFormatter("%{message}") - - // GlogFormatter mimics the glog format - GlogFormatter = MustStringFormatter("%{level:.1s}%{time:0102 15:04:05.999999} %{pid} %{shortfile}] %{message}") -) - -// SetFormatter sets the default formatter for all new backends. A backend will -// fetch this value once it is needed to format a record. Note that backends -// will cache the formatter after the first point. For now, make sure to set -// the formatter before logging. -func SetFormatter(f Formatter) { - formatter.Lock() - defer formatter.Unlock() - formatter.def = f -} - -var formatRe = regexp.MustCompile(`%{([a-z]+)(?::(.*?[^\\]))?}`) - -type part struct { - verb fmtVerb - layout string -} - -// stringFormatter contains a list of parts which explains how to build the -// formatted string passed on to the logging backend. -type stringFormatter struct { - parts []part -} - -// NewStringFormatter returns a new Formatter which outputs the log record as a -// string based on the 'verbs' specified in the format string. -// -// The verbs: -// -// General: -// %{id} Sequence number for log message (uint64). -// %{pid} Process id (int) -// %{time} Time when log occurred (time.Time) -// %{level} Log level (Level) -// %{module} Module (string) -// %{program} Basename of os.Args[0] (string) -// %{message} Message (string) -// %{longfile} Full file name and line number: /a/b/c/d.go:23 -// %{shortfile} Final file name element and line number: d.go:23 -// %{callpath} Callpath like main.a.b.c...c "..." meaning recursive call ~. meaning truncated path -// %{color} ANSI color based on log level -// -// For normal types, the output can be customized by using the 'verbs' defined -// in the fmt package, eg. '%{id:04d}' to make the id output be '%04d' as the -// format string. -// -// For time.Time, use the same layout as time.Format to change the time format -// when output, eg "2006-01-02T15:04:05.999Z-07:00". -// -// For the 'color' verb, the output can be adjusted to either use bold colors, -// i.e., '%{color:bold}' or to reset the ANSI attributes, i.e., -// '%{color:reset}' Note that if you use the color verb explicitly, be sure to -// reset it or else the color state will persist past your log message. e.g., -// "%{color:bold}%{time:15:04:05} %{level:-8s}%{color:reset} %{message}" will -// just colorize the time and level, leaving the message uncolored. -// -// For the 'callpath' verb, the output can be adjusted to limit the printing -// the stack depth. i.e. '%{callpath:3}' will print '~.a.b.c' -// -// Colors on Windows is unfortunately not supported right now and is currently -// a no-op. -// -// There's also a couple of experimental 'verbs'. These are exposed to get -// feedback and needs a bit of tinkering. Hence, they might change in the -// future. -// -// Experimental: -// %{longpkg} Full package path, eg. github.com/go-logging -// %{shortpkg} Base package path, eg. go-logging -// %{longfunc} Full function name, eg. littleEndian.PutUint32 -// %{shortfunc} Base function name, eg. PutUint32 -// %{callpath} Call function path, eg. main.a.b.c -func NewStringFormatter(format string) (Formatter, error) { - var fmter = &stringFormatter{} - - // Find the boundaries of all %{vars} - matches := formatRe.FindAllStringSubmatchIndex(format, -1) - if matches == nil { - return nil, errors.New("logger: invalid log format: " + format) - } - - // Collect all variables and static text for the format - prev := 0 - for _, m := range matches { - start, end := m[0], m[1] - if start > prev { - fmter.add(fmtVerbStatic, format[prev:start]) - } - - name := format[m[2]:m[3]] - verb := getFmtVerbByName(name) - if verb == fmtVerbUnknown { - return nil, errors.New("logger: unknown variable: " + name) - } - - // Handle layout customizations or use the default. If this is not for the - // time, color formatting or callpath, we need to prefix with %. - layout := defaultVerbsLayout[verb] - if m[4] != -1 { - layout = format[m[4]:m[5]] - } - if verb != fmtVerbTime && verb != fmtVerbLevelColor && verb != fmtVerbCallpath { - layout = "%" + layout - } - - fmter.add(verb, layout) - prev = end - } - end := format[prev:] - if end != "" { - fmter.add(fmtVerbStatic, end) - } - - // Make a test run to make sure we can format it correctly. - t, err := time.Parse(time.RFC3339, "2010-02-04T21:00:57-08:00") - if err != nil { - panic(err) - } - testFmt := "hello %s" - r := &Record{ - ID: 12345, - Time: t, - Module: "logger", - Args: []interface{}{"go"}, - fmt: &testFmt, - } - if err := fmter.Format(0, r, &bytes.Buffer{}); err != nil { - return nil, err - } - - return fmter, nil -} - -// MustStringFormatter is equivalent to NewStringFormatter with a call to panic -// on error. -func MustStringFormatter(format string) Formatter { - f, err := NewStringFormatter(format) - if err != nil { - panic("Failed to initialized string formatter: " + err.Error()) - } - return f -} - -func (f *stringFormatter) add(verb fmtVerb, layout string) { - f.parts = append(f.parts, part{verb, layout}) -} - -func (f *stringFormatter) Format(calldepth int, r *Record, output io.Writer) error { - for _, part := range f.parts { - if part.verb == fmtVerbStatic { - output.Write([]byte(part.layout)) - } else if part.verb == fmtVerbTime { - output.Write([]byte(r.Time.Format(part.layout))) - } else if part.verb == fmtVerbLevelColor { - doFmtVerbLevelColor(part.layout, r.Level, output) - } else if part.verb == fmtVerbCallpath { - depth, err := strconv.Atoi(part.layout) - if err != nil { - depth = 0 - } - output.Write([]byte(formatCallpath(calldepth+1, depth))) - } else { - var v interface{} - switch part.verb { - case fmtVerbLevel: - v = r.Level - break - case fmtVerbID: - v = r.ID - break - case fmtVerbPid: - v = pid - break - case fmtVerbProgram: - v = program - break - case fmtVerbModule: - v = r.Module - break - case fmtVerbMessage: - v = r.Message() - break - case fmtVerbLongfile, fmtVerbShortfile: - _, file, line, ok := runtime.Caller(calldepth + 1) - if !ok { - file = "???" - line = 0 - } else if part.verb == fmtVerbShortfile { - file = filepath.Base(file) - } - v = fmt.Sprintf("%s:%d", file, line) - case fmtVerbLongfunc, fmtVerbShortfunc, - fmtVerbLongpkg, fmtVerbShortpkg: - // TODO cache pc - v = "???" - if pc, _, _, ok := runtime.Caller(calldepth + 1); ok { - if f := runtime.FuncForPC(pc); f != nil { - v = formatFuncName(part.verb, f.Name()) - } - } - default: - panic("unhandled format part") - } - fmt.Fprintf(output, part.layout, v) - } - } - return nil -} - -// formatFuncName tries to extract certain part of the runtime formatted -// function name to some pre-defined variation. -// -// This function is known to not work properly if the package path or name -// contains a dot. -func formatFuncName(v fmtVerb, f string) string { - i := strings.LastIndex(f, "/") - j := strings.Index(f[i+1:], ".") - if j < 1 { - return "???" - } - pkg, fun := f[:i+j+1], f[i+j+2:] - switch v { - case fmtVerbLongpkg: - return pkg - case fmtVerbShortpkg: - return path.Base(pkg) - case fmtVerbLongfunc: - return fun - case fmtVerbShortfunc: - i = strings.LastIndex(fun, ".") - return fun[i+1:] - } - panic("unexpected func formatter") -} - -func formatCallpath(calldepth int, depth int) string { - v := "" - callers := make([]uintptr, 64) - n := runtime.Callers(calldepth+2, callers) - oldPc := callers[n-1] - - start := n - 3 - if depth > 0 && start >= depth { - start = depth - 1 - v += "~." - } - recursiveCall := false - for i := start; i >= 0; i-- { - pc := callers[i] - if oldPc == pc { - recursiveCall = true - continue - } - oldPc = pc - if recursiveCall { - recursiveCall = false - v += ".." - } - if i < start { - v += "." - } - if f := runtime.FuncForPC(pc); f != nil { - v += formatFuncName(fmtVerbShortfunc, f.Name()) - } - } - return v -} - -// backendFormatter combines a backend with a specific formatter making it -// possible to have different log formats for different backends. -type backendFormatter struct { - b Backend - f Formatter -} - -// NewBackendFormatter creates a new backend which makes all records that -// passes through it beeing formatted by the specific formatter. -func NewBackendFormatter(b Backend, f Formatter) Backend { - return &backendFormatter{b, f} -} - -// Log implements the Log function required by the Backend interface. -func (bf *backendFormatter) Log(level Level, calldepth int, r *Record) error { - // Make a shallow copy of the record and replace any formatter - r2 := *r - r2.formatter = bf.f - return bf.b.Log(level, calldepth+1, &r2) -} diff --git a/format_test.go b/format_test.go deleted file mode 100644 index c008e9e..0000000 --- a/format_test.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import ( - "bytes" - "testing" -) - -func TestFormat(t *testing.T) { - backend := InitForTesting(DEBUG) - - f, err := NewStringFormatter("%{shortfile} %{time:2006-01-02T15:04:05} %{level:.1s} %{id:04d} %{module} %{message}") - if err != nil { - t.Fatalf("failed to set format: %s", err) - } - SetFormatter(f) - - log := MustGetLogger("module") - log.Debug("hello") - - line := MemoryRecordN(backend, 0).Formatted(0) - if "format_test.go:24 1970-01-01T00:00:00 D 0001 module hello" != line { - t.Errorf("Unexpected format: %s", line) - } -} - -func logAndGetLine(backend *MemoryBackend) string { - MustGetLogger("foo").Debug("hello") - return MemoryRecordN(backend, 0).Formatted(1) -} - -func getLastLine(backend *MemoryBackend) string { - return MemoryRecordN(backend, 0).Formatted(1) -} - -func realFunc(backend *MemoryBackend) string { - return logAndGetLine(backend) -} - -type structFunc struct{} - -func (structFunc) Log(backend *MemoryBackend) string { - return logAndGetLine(backend) -} - -func TestRealFuncFormat(t *testing.T) { - backend := InitForTesting(DEBUG) - SetFormatter(MustStringFormatter("%{shortfunc}")) - - line := realFunc(backend) - if "realFunc" != line { - t.Errorf("Unexpected format: %s", line) - } -} - -func TestStructFuncFormat(t *testing.T) { - backend := InitForTesting(DEBUG) - SetFormatter(MustStringFormatter("%{longfunc}")) - - var x structFunc - line := x.Log(backend) - if "structFunc.Log" != line { - t.Errorf("Unexpected format: %s", line) - } -} - -func TestVarFuncFormat(t *testing.T) { - backend := InitForTesting(DEBUG) - SetFormatter(MustStringFormatter("%{shortfunc}")) - - var varFunc = func() string { - return logAndGetLine(backend) - } - - line := varFunc() - if "???" == line || "TestVarFuncFormat" == line || "varFunc" == line { - t.Errorf("Unexpected format: %s", line) - } -} - -func TestFormatFuncName(t *testing.T) { - var tests = []struct { - filename string - longpkg string - shortpkg string - longfunc string - shortfunc string - }{ - {"", - "???", - "???", - "???", - "???"}, - {"main", - "???", - "???", - "???", - "???"}, - {"main.", - "main", - "main", - "", - ""}, - {"main.main", - "main", - "main", - "main", - "main"}, - {"github.com/op/go-logging.func·001", - "github.com/op/go-logging", - "go-logging", - "func·001", - "func·001"}, - {"github.com/op/go-logging.stringFormatter.Format", - "github.com/op/go-logging", - "go-logging", - "stringFormatter.Format", - "Format"}, - } - - var v string - for _, test := range tests { - v = formatFuncName(fmtVerbLongpkg, test.filename) - if test.longpkg != v { - t.Errorf("%s != %s", test.longpkg, v) - } - v = formatFuncName(fmtVerbShortpkg, test.filename) - if test.shortpkg != v { - t.Errorf("%s != %s", test.shortpkg, v) - } - v = formatFuncName(fmtVerbLongfunc, test.filename) - if test.longfunc != v { - t.Errorf("%s != %s", test.longfunc, v) - } - v = formatFuncName(fmtVerbShortfunc, test.filename) - if test.shortfunc != v { - t.Errorf("%s != %s", test.shortfunc, v) - } - } -} - -func TestBackendFormatter(t *testing.T) { - InitForTesting(DEBUG) - - // Create two backends and wrap one of the with a backend formatter - b1 := NewMemoryBackend(1) - b2 := NewMemoryBackend(1) - - f := MustStringFormatter("%{level} %{message}") - bf := NewBackendFormatter(b2, f) - - SetBackend(b1, bf) - - log := MustGetLogger("module") - log.Info("foo") - if "foo" != getLastLine(b1) { - t.Errorf("Unexpected line: %s", getLastLine(b1)) - } - if "INFO foo" != getLastLine(b2) { - t.Errorf("Unexpected line: %s", getLastLine(b2)) - } -} - -func BenchmarkStringFormatter(b *testing.B) { - fmt := "%{time:2006-01-02T15:04:05} %{level:.1s} %{id:04d} %{module} %{message}" - f := MustStringFormatter(fmt) - - backend := InitForTesting(DEBUG) - buf := &bytes.Buffer{} - log := MustGetLogger("module") - log.Debug("") - record := MemoryRecordN(backend, 0) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := f.Format(1, record, buf); err != nil { - b.Fatal(err) - buf.Truncate(0) - } - } -} diff --git a/level.go b/level.go deleted file mode 100644 index 98dd191..0000000 --- a/level.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import ( - "errors" - "strings" - "sync" -) - -// ErrInvalidLogLevel is used when an invalid log level has been used. -var ErrInvalidLogLevel = errors.New("logger: invalid log level") - -// Level defines all available log levels for log messages. -type Level int - -// Log levels. -const ( - CRITICAL Level = iota - ERROR - WARNING - NOTICE - INFO - DEBUG -) - -var levelNames = []string{ - "CRITICAL", - "ERROR", - "WARNING", - "NOTICE", - "INFO", - "DEBUG", -} - -// String returns the string representation of a logging level. -func (p Level) String() string { - return levelNames[p] -} - -// LogLevel returns the log level from a string representation. -func LogLevel(level string) (Level, error) { - for i, name := range levelNames { - if strings.EqualFold(name, level) { - return Level(i), nil - } - } - return ERROR, ErrInvalidLogLevel -} - -// Leveled interface is the interface required to be able to add leveled -// logging. -type Leveled interface { - GetLevel(string) Level - SetLevel(Level, string) - IsEnabledFor(Level, string) bool -} - -// LeveledBackend is a log backend with additional knobs for setting levels on -// individual modules to different levels. -type LeveledBackend interface { - Backend - Leveled -} - -type moduleLeveled struct { - levels map[string]Level - backend Backend - formatter Formatter - once sync.Once -} - -// AddModuleLevel wraps a log backend with knobs to have different log levels -// for different modules. -func AddModuleLevel(backend Backend) LeveledBackend { - var leveled LeveledBackend - var ok bool - if leveled, ok = backend.(LeveledBackend); !ok { - leveled = &moduleLeveled{ - levels: make(map[string]Level), - backend: backend, - } - } - return leveled -} - -// GetLevel returns the log level for the given module. -func (l *moduleLeveled) GetLevel(module string) Level { - level, exists := l.levels[module] - if exists == false { - level, exists = l.levels[""] - // no configuration exists, default to debug - if exists == false { - level = DEBUG - } - } - return level -} - -// SetLevel sets the log level for the given module. -func (l *moduleLeveled) SetLevel(level Level, module string) { - l.levels[module] = level -} - -// IsEnabledFor will return true if logging is enabled for the given module. -func (l *moduleLeveled) IsEnabledFor(level Level, module string) bool { - return level <= l.GetLevel(module) -} - -func (l *moduleLeveled) Log(level Level, calldepth int, rec *Record) (err error) { - if l.IsEnabledFor(level, rec.Module) { - // TODO get rid of traces of formatter here. BackendFormatter should be used. - rec.formatter = l.getFormatterAndCacheCurrent() - err = l.backend.Log(level, calldepth+1, rec) - } - return -} - -func (l *moduleLeveled) getFormatterAndCacheCurrent() Formatter { - l.once.Do(func() { - if l.formatter == nil { - l.formatter = getFormatter() - } - }) - return l.formatter -} diff --git a/level_test.go b/level_test.go deleted file mode 100644 index c8f9a37..0000000 --- a/level_test.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import "testing" - -func TestLevelString(t *testing.T) { - // Make sure all levels can be converted from string -> constant -> string - for _, name := range levelNames { - level, err := LogLevel(name) - if err != nil { - t.Errorf("failed to get level: %v", err) - continue - } - - if level.String() != name { - t.Errorf("invalid level conversion: %v != %v", level, name) - } - } -} - -func TestLevelLogLevel(t *testing.T) { - tests := []struct { - expected Level - level string - }{ - {-1, "bla"}, - {INFO, "iNfO"}, - {ERROR, "error"}, - {WARNING, "warninG"}, - } - - for _, test := range tests { - level, err := LogLevel(test.level) - if err != nil { - if test.expected == -1 { - continue - } else { - t.Errorf("failed to convert %s: %s", test.level, err) - } - } - if test.expected != level { - t.Errorf("failed to convert %s to level: %s != %s", test.level, test.expected, level) - } - } -} - -func TestLevelModuleLevel(t *testing.T) { - backend := NewMemoryBackend(128) - - leveled := AddModuleLevel(backend) - leveled.SetLevel(NOTICE, "") - leveled.SetLevel(ERROR, "foo") - leveled.SetLevel(INFO, "foo.bar") - leveled.SetLevel(WARNING, "bar") - - expected := []struct { - level Level - module string - }{ - {NOTICE, ""}, - {NOTICE, "something"}, - {ERROR, "foo"}, - {INFO, "foo.bar"}, - {WARNING, "bar"}, - } - - for _, e := range expected { - actual := leveled.GetLevel(e.module) - if e.level != actual { - t.Errorf("unexpected level in %s: %s != %s", e.module, e.level, actual) - } - } -} diff --git a/log_nix.go b/log_nix.go deleted file mode 100644 index 4ff2ab1..0000000 --- a/log_nix.go +++ /dev/null @@ -1,109 +0,0 @@ -// +build !windows - -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import ( - "bytes" - "fmt" - "io" - "log" -) - -type color int - -const ( - ColorBlack = iota + 30 - ColorRed - ColorGreen - ColorYellow - ColorBlue - ColorMagenta - ColorCyan - ColorWhite -) - -var ( - colors = []string{ - CRITICAL: ColorSeq(ColorMagenta), - ERROR: ColorSeq(ColorRed), - WARNING: ColorSeq(ColorYellow), - NOTICE: ColorSeq(ColorGreen), - DEBUG: ColorSeq(ColorCyan), - } - boldcolors = []string{ - CRITICAL: ColorSeqBold(ColorMagenta), - ERROR: ColorSeqBold(ColorRed), - WARNING: ColorSeqBold(ColorYellow), - NOTICE: ColorSeqBold(ColorGreen), - DEBUG: ColorSeqBold(ColorCyan), - } -) - -// LogBackend utilizes the standard log module. -type LogBackend struct { - Logger *log.Logger - Color bool - ColorConfig []string -} - -// NewLogBackend creates a new LogBackend. -func NewLogBackend(out io.Writer, prefix string, flag int) *LogBackend { - return &LogBackend{Logger: log.New(out, prefix, flag)} -} - -// Log implements the Backend interface. -func (b *LogBackend) Log(level Level, calldepth int, rec *Record) error { - if b.Color { - col := colors[level] - if len(b.ColorConfig) > int(level) && b.ColorConfig[level] != "" { - col = b.ColorConfig[level] - } - - buf := &bytes.Buffer{} - buf.Write([]byte(col)) - buf.Write([]byte(rec.Formatted(calldepth + 1))) - buf.Write([]byte("\033[0m")) - // For some reason, the Go logger arbitrarily decided "2" was the correct - // call depth... - return b.Logger.Output(calldepth+2, buf.String()) - } - - return b.Logger.Output(calldepth+2, rec.Formatted(calldepth+1)) -} - -// ConvertColors takes a list of ints representing colors for log levels and -// converts them into strings for ANSI color formatting -func ConvertColors(colors []int, bold bool) []string { - converted := []string{} - for _, i := range colors { - if bold { - converted = append(converted, ColorSeqBold(color(i))) - } else { - converted = append(converted, ColorSeq(color(i))) - } - } - - return converted -} - -func ColorSeq(color color) string { - return fmt.Sprintf("\033[%dm", int(color)) -} - -func ColorSeqBold(color color) string { - return fmt.Sprintf("\033[%d;1m", int(color)) -} - -func doFmtVerbLevelColor(layout string, level Level, output io.Writer) { - if layout == "bold" { - output.Write([]byte(boldcolors[level])) - } else if layout == "reset" { - output.Write([]byte("\033[0m")) - } else { - output.Write([]byte(colors[level])) - } -} diff --git a/log_test.go b/log_test.go deleted file mode 100644 index c7a645f..0000000 --- a/log_test.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import ( - "bytes" - "io/ioutil" - "log" - "strings" - "testing" -) - -func TestLogCalldepth(t *testing.T) { - buf := &bytes.Buffer{} - SetBackend(NewLogBackend(buf, "", log.Lshortfile)) - SetFormatter(MustStringFormatter("%{shortfile} %{level} %{message}")) - - log := MustGetLogger("test") - log.Info("test filename") - - parts := strings.SplitN(buf.String(), " ", 2) - - // Verify that the correct filename is registered by the stdlib logger - if !strings.HasPrefix(parts[0], "log_test.go:") { - t.Errorf("incorrect filename: %s", parts[0]) - } - // Verify that the correct filename is registered by go-logging - if !strings.HasPrefix(parts[1], "log_test.go:") { - t.Errorf("incorrect filename: %s", parts[1]) - } -} - -func c(log *Logger) { log.Info("test callpath") } -func b(log *Logger) { c(log) } -func a(log *Logger) { b(log) } - -func rec(log *Logger, r int) { - if r == 0 { - a(log) - return - } - rec(log, r-1) -} - -func testCallpath(t *testing.T, format string, expect string) { - buf := &bytes.Buffer{} - SetBackend(NewLogBackend(buf, "", log.Lshortfile)) - SetFormatter(MustStringFormatter(format)) - - logger := MustGetLogger("test") - rec(logger, 6) - - parts := strings.SplitN(buf.String(), " ", 3) - - // Verify that the correct filename is registered by the stdlib logger - if !strings.HasPrefix(parts[0], "log_test.go:") { - t.Errorf("incorrect filename: %s", parts[0]) - } - // Verify that the correct callpath is registered by go-logging - if !strings.HasPrefix(parts[1], expect) { - t.Errorf("incorrect callpath: %s", parts[1]) - } - // Verify that the correct message is registered by go-logging - if !strings.HasPrefix(parts[2], "test callpath") { - t.Errorf("incorrect message: %s", parts[2]) - } -} - -func TestLogCallpath(t *testing.T) { - testCallpath(t, "%{callpath} %{message}", "TestLogCallpath.testCallpath.rec...rec.a.b.c") - testCallpath(t, "%{callpath:-1} %{message}", "TestLogCallpath.testCallpath.rec...rec.a.b.c") - testCallpath(t, "%{callpath:0} %{message}", "TestLogCallpath.testCallpath.rec...rec.a.b.c") - testCallpath(t, "%{callpath:1} %{message}", "~.c") - testCallpath(t, "%{callpath:2} %{message}", "~.b.c") - testCallpath(t, "%{callpath:3} %{message}", "~.a.b.c") -} - -func BenchmarkLogMemoryBackendIgnored(b *testing.B) { - backend := SetBackend(NewMemoryBackend(1024)) - backend.SetLevel(INFO, "") - RunLogBenchmark(b) -} - -func BenchmarkLogMemoryBackend(b *testing.B) { - backend := SetBackend(NewMemoryBackend(1024)) - backend.SetLevel(DEBUG, "") - RunLogBenchmark(b) -} - -func BenchmarkLogChannelMemoryBackend(b *testing.B) { - channelBackend := NewChannelMemoryBackend(1024) - backend := SetBackend(channelBackend) - backend.SetLevel(DEBUG, "") - RunLogBenchmark(b) - channelBackend.Flush() -} - -func BenchmarkLogLeveled(b *testing.B) { - backend := SetBackend(NewLogBackend(ioutil.Discard, "", 0)) - backend.SetLevel(INFO, "") - - RunLogBenchmark(b) -} - -func BenchmarkLogLogBackend(b *testing.B) { - backend := SetBackend(NewLogBackend(ioutil.Discard, "", 0)) - backend.SetLevel(DEBUG, "") - RunLogBenchmark(b) -} - -func BenchmarkLogLogBackendColor(b *testing.B) { - colorizer := NewLogBackend(ioutil.Discard, "", 0) - colorizer.Color = true - backend := SetBackend(colorizer) - backend.SetLevel(DEBUG, "") - RunLogBenchmark(b) -} - -func BenchmarkLogLogBackendStdFlags(b *testing.B) { - backend := SetBackend(NewLogBackend(ioutil.Discard, "", log.LstdFlags)) - backend.SetLevel(DEBUG, "") - RunLogBenchmark(b) -} - -func BenchmarkLogLogBackendLongFileFlag(b *testing.B) { - backend := SetBackend(NewLogBackend(ioutil.Discard, "", log.Llongfile)) - backend.SetLevel(DEBUG, "") - RunLogBenchmark(b) -} - -func RunLogBenchmark(b *testing.B) { - password := Password("foo") - log := MustGetLogger("test") - - b.ResetTimer() - for i := 0; i < b.N; i++ { - log.Debug("log line for %d and this is rectified: %s", i, password) - } -} - -func BenchmarkLogFixed(b *testing.B) { - backend := SetBackend(NewLogBackend(ioutil.Discard, "", 0)) - backend.SetLevel(DEBUG, "") - - RunLogBenchmarkFixedString(b) -} - -func BenchmarkLogFixedIgnored(b *testing.B) { - backend := SetBackend(NewLogBackend(ioutil.Discard, "", 0)) - backend.SetLevel(INFO, "") - RunLogBenchmarkFixedString(b) -} - -func RunLogBenchmarkFixedString(b *testing.B) { - log := MustGetLogger("test") - - b.ResetTimer() - for i := 0; i < b.N; i++ { - log.Debug("some random fixed text") - } -} diff --git a/log_windows.go b/log_windows.go deleted file mode 100644 index b8dc92c..0000000 --- a/log_windows.go +++ /dev/null @@ -1,107 +0,0 @@ -// +build windows -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import ( - "bytes" - "io" - "log" - "syscall" -) - -var ( - kernel32DLL = syscall.NewLazyDLL("kernel32.dll") - setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute") -) - -// Character attributes -// Note: -// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan). -// Clearing all foreground or background colors results in black; setting all creates white. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes. -const ( - fgBlack = 0x0000 - fgBlue = 0x0001 - fgGreen = 0x0002 - fgCyan = 0x0003 - fgRed = 0x0004 - fgMagenta = 0x0005 - fgYellow = 0x0006 - fgWhite = 0x0007 - fgIntensity = 0x0008 - fgMask = 0x000F -) - -var ( - colors = []uint16{ - INFO: fgWhite, - CRITICAL: fgMagenta, - ERROR: fgRed, - WARNING: fgYellow, - NOTICE: fgGreen, - DEBUG: fgCyan, - } - boldcolors = []uint16{ - INFO: fgWhite | fgIntensity, - CRITICAL: fgMagenta | fgIntensity, - ERROR: fgRed | fgIntensity, - WARNING: fgYellow | fgIntensity, - NOTICE: fgGreen | fgIntensity, - DEBUG: fgCyan | fgIntensity, - } -) - -type file interface { - Fd() uintptr -} - -// LogBackend utilizes the standard log module. -type LogBackend struct { - Logger *log.Logger - Color bool - - // f is set to a non-nil value if the underlying writer which logs writes to - // implements the file interface. This makes us able to colorise the output. - f file -} - -// NewLogBackend creates a new LogBackend. -func NewLogBackend(out io.Writer, prefix string, flag int) *LogBackend { - b := &LogBackend{Logger: log.New(out, prefix, flag)} - - // Unfortunately, the API used only takes an io.Writer where the Windows API - // need the actual fd to change colors. - if f, ok := out.(file); ok { - b.f = f - } - - return b -} - -func (b *LogBackend) Log(level Level, calldepth int, rec *Record) error { - if b.Color && b.f != nil { - buf := &bytes.Buffer{} - setConsoleTextAttribute(b.f, colors[level]) - buf.Write([]byte(rec.Formatted(calldepth + 1))) - err := b.Logger.Output(calldepth+2, buf.String()) - setConsoleTextAttribute(b.f, fgWhite) - return err - } - return b.Logger.Output(calldepth+2, rec.Formatted(calldepth+1)) -} - -// setConsoleTextAttribute sets the attributes of characters written to the -// console screen buffer by the WriteFile or WriteConsole function. -// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx. -func setConsoleTextAttribute(f file, attribute uint16) bool { - ok, _, _ := setConsoleTextAttributeProc.Call(f.Fd(), uintptr(attribute), 0) - return ok != 0 -} - -func doFmtVerbLevelColor(layout string, level Level, output io.Writer) { - // TODO not supported on Windows since the io.Writer here is actually a - // bytes.Buffer. -} diff --git a/logger.go b/logger.go deleted file mode 100644 index eb375a7..0000000 --- a/logger.go +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package logging implements a logging infrastructure for Go. It supports -// different logging backends like syslog, file and memory. Multiple backends -// can be utilized with different log levels per backend and logger. -package logging - -import ( - "bytes" - "fmt" - "log" - "os" - "strings" - "sync/atomic" - "time" -) - -// Redactor is an interface for types that may contain sensitive information -// (like passwords), which shouldn't be printed to the log. The idea was found -// in relog as part of the vitness project. -type Redactor interface { - Redacted() interface{} -} - -// Redact returns a string of * having the same length as s. -func Redact(s string) string { - return strings.Repeat("*", len(s)) -} - -var ( - // Sequence number is incremented and utilized for all log records created. - sequenceNo uint64 - - // timeNow is a customizable for testing purposes. - timeNow = time.Now -) - -// Record represents a log record and contains the timestamp when the record -// was created, an increasing id, filename and line and finally the actual -// formatted log line. -type Record struct { - ID uint64 - Time time.Time - Module string - Level Level - Args []interface{} - - // message is kept as a pointer to have shallow copies update this once - // needed. - message *string - fmt *string - formatter Formatter - formatted string -} - -// Formatted returns the formatted log record string. -func (r *Record) Formatted(calldepth int) string { - if r.formatted == "" { - var buf bytes.Buffer - r.formatter.Format(calldepth+1, r, &buf) - r.formatted = buf.String() - } - return r.formatted -} - -// Message returns the log record message. -func (r *Record) Message() string { - if r.message == nil { - // Redact the arguments that implements the Redactor interface - for i, arg := range r.Args { - if redactor, ok := arg.(Redactor); ok == true { - r.Args[i] = redactor.Redacted() - } - } - var buf bytes.Buffer - if r.fmt != nil { - fmt.Fprintf(&buf, *r.fmt, r.Args...) - } else { - // use Fprintln to make sure we always get space between arguments - fmt.Fprintln(&buf, r.Args...) - buf.Truncate(buf.Len() - 1) // strip newline - } - msg := buf.String() - r.message = &msg - } - return *r.message -} - - -//type Log interface { -// Critical(args ...interface{}) -// Criticalf(format string, args ...interface{}) -// Debug(args ...interface{}) -// Debugf(format string, args ...interface{}) -// Error(args ...interface{}) -// Errorf(format string, args ...interface{}) -// Fatal(args ...interface{}) -// Fatalf(format string, args ...interface{}) -// Info(args ...interface{}) -// Infof(format string, args ...interface{}) -// Notice(args ...interface{}) -// Noticef(format string, args ...interface{}) -// Panic(args ...interface{}) -// Panicf(format string, args ...interface{}) -// Warning(args ...interface{}) -// Warningf(format string, args ...interface{}) -//} - -// Logger is the actual logger which creates log records based on the functions -// called and passes them to the underlying logging backend. -type Logger struct { - Module string - backend LeveledBackend - haveBackend bool - - // ExtraCallDepth can be used to add additional call depth when getting the - // calling function. This is normally used when wrapping a logger. - ExtraCalldepth int -} - -// SetBackend overrides any previously defined backend for this logger. -func (l *Logger) SetBackend(backend LeveledBackend) { - l.backend = backend - l.haveBackend = true -} - -// TODO call NewLogger and remove MustGetLogger? - -// GetLogger creates and returns a Logger object based on the module name. -func GetLogger(module string) (*Logger, error) { - return &Logger{Module: module}, nil -} - -// MustGetLogger is like GetLogger but panics if the logger can't be created. -// It simplifies safe initialization of a global logger for eg. a package. -func MustGetLogger(module string) *Logger { - logger, err := GetLogger(module) - if err != nil { - panic("logger: " + module + ": " + err.Error()) - } - return logger -} - -// Reset restores the internal state of the logging library. -func Reset() { - // TODO make a global Init() method to be less magic? or make it such that - // if there's no backends at all configured, we could use some tricks to - // automatically setup backends based if we have a TTY or not. - sequenceNo = 0 - b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags)) - b.SetLevel(DEBUG, "") - SetFormatter(DefaultFormatter) - timeNow = time.Now -} - -// IsEnabledFor returns true if the logger is enabled for the given level. -func (l *Logger) IsEnabledFor(level Level) bool { - return defaultBackend.IsEnabledFor(level, l.Module) -} - -func (l *Logger) log(lvl Level, format *string, args ...interface{}) { - if !l.IsEnabledFor(lvl) { - return - } - - // Create the logging record and pass it in to the backend - record := &Record{ - ID: atomic.AddUint64(&sequenceNo, 1), - Time: timeNow(), - Module: l.Module, - Level: lvl, - fmt: format, - Args: args, - } - - // TODO use channels to fan out the records to all backends? - // TODO in case of errors, do something (tricky) - - // calldepth=2 brings the stack up to the caller of the level - // methods, Info(), Fatal(), etc. - // ExtraCallDepth allows this to be extended further up the stack in case we - // are wrapping these methods, eg. to expose them package level - if l.haveBackend { - l.backend.Log(lvl, 2+l.ExtraCalldepth, record) - return - } - - defaultBackend.Log(lvl, 2+l.ExtraCalldepth, record) -} - -// Fatal is equivalent to l.Critical(fmt.Sprint()) followed by a call to os.Exit(1). -func (l *Logger) Fatal(args ...interface{}) { - l.log(CRITICAL, nil, args...) - os.Exit(1) -} - -// Fatalf is equivalent to l.Critical followed by a call to os.Exit(1). -func (l *Logger) Fatalf(format string, args ...interface{}) { - l.log(CRITICAL, &format, args...) - os.Exit(1) -} - -// Panic is equivalent to l.Critical(fmt.Sprint()) followed by a call to panic(). -func (l *Logger) Panic(args ...interface{}) { - l.log(CRITICAL, nil, args...) - panic(fmt.Sprint(args...)) -} - -// Panicf is equivalent to l.Critical followed by a call to panic(). -func (l *Logger) Panicf(format string, args ...interface{}) { - l.log(CRITICAL, &format, args...) - panic(fmt.Sprintf(format, args...)) -} - -// Critical logs a message using CRITICAL as log level. -func (l *Logger) Critical(args ...interface{}) { - l.log(CRITICAL, nil, args...) -} - -// Criticalf logs a message using CRITICAL as log level. -func (l *Logger) Criticalf(format string, args ...interface{}) { - l.log(CRITICAL, &format, args...) -} - -// Error logs a message using ERROR as log level. -func (l *Logger) Error(args ...interface{}) { - l.log(ERROR, nil, args...) -} - -// Errorf logs a message using ERROR as log level. -func (l *Logger) Errorf(format string, args ...interface{}) { - l.log(ERROR, &format, args...) -} - -// Warning logs a message using WARNING as log level. -func (l *Logger) Warning(args ...interface{}) { - l.log(WARNING, nil, args...) -} - -// Warningf logs a message using WARNING as log level. -func (l *Logger) Warningf(format string, args ...interface{}) { - l.log(WARNING, &format, args...) -} - -// Notice logs a message using NOTICE as log level. -func (l *Logger) Notice(args ...interface{}) { - l.log(NOTICE, nil, args...) -} - -// Noticef logs a message using NOTICE as log level. -func (l *Logger) Noticef(format string, args ...interface{}) { - l.log(NOTICE, &format, args...) -} - -// Info logs a message using INFO as log level. -func (l *Logger) Info(args ...interface{}) { - l.log(INFO, nil, args...) -} - -// Infof logs a message using INFO as log level. -func (l *Logger) Infof(format string, args ...interface{}) { - l.log(INFO, &format, args...) -} - -// Debug logs a message using DEBUG as log level. -func (l *Logger) Debug(args ...interface{}) { - l.log(DEBUG, nil, args...) -} - -// Debugf logs a message using DEBUG as log level. -func (l *Logger) Debugf(format string, args ...interface{}) { - l.log(DEBUG, &format, args...) -} - -func init() { - Reset() -} diff --git a/logger_test.go b/logger_test.go deleted file mode 100644 index b9f7fe7..0000000 --- a/logger_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import "testing" - -type Password string - -func (p Password) Redacted() interface{} { - return Redact(string(p)) -} - -func TestSequenceNoOverflow(t *testing.T) { - // Forcefully set the next sequence number to the maximum - backend := InitForTesting(DEBUG) - sequenceNo = ^uint64(0) - - log := MustGetLogger("test") - log.Debug("test") - - if MemoryRecordN(backend, 0).ID != 0 { - t.Errorf("Unexpected sequence no: %v", MemoryRecordN(backend, 0).ID) - } -} - -func TestRedact(t *testing.T) { - backend := InitForTesting(DEBUG) - password := Password("123456") - log := MustGetLogger("test") - log.Debug("foo", password) - if "foo ******" != MemoryRecordN(backend, 0).Formatted(0) { - t.Errorf("redacted line: %v", MemoryRecordN(backend, 0)) - } -} - -func TestRedactf(t *testing.T) { - backend := InitForTesting(DEBUG) - password := Password("123456") - log := MustGetLogger("test") - log.Debugf("foo %s", password) - if "foo ******" != MemoryRecordN(backend, 0).Formatted(0) { - t.Errorf("redacted line: %v", MemoryRecordN(backend, 0).Formatted(0)) - } -} - -func TestPrivateBackend(t *testing.T) { - stdBackend := InitForTesting(DEBUG) - log := MustGetLogger("test") - privateBackend := NewMemoryBackend(10240) - lvlBackend := AddModuleLevel(privateBackend) - lvlBackend.SetLevel(DEBUG, "") - log.SetBackend(lvlBackend) - log.Debug("to private backend") - if stdBackend.size > 0 { - t.Errorf("something in stdBackend, size of backend: %d", stdBackend.size) - } - if "to private baсkend" == MemoryRecordN(privateBackend, 0).Formatted(0) { - t.Error("logged to defaultBackend:", MemoryRecordN(privateBackend, 0)) - } -} diff --git a/logging.go b/logging.go new file mode 100644 index 0000000..fe4f2bb --- /dev/null +++ b/logging.go @@ -0,0 +1,28 @@ +package logging + +// +// Who write the logs to output +// +type Printer interface { + Printf(format string, args ...interface{}) + Print(args ...interface{}) +} + +// +// The package logger interface, you can create as many impl as you want +// +type Log interface { + + Debug(args ...interface{}) + Debugf(format string, args ...interface{}) + + Info(args ...interface{}) + Infof(format string, args ...interface{}) + + Warning(args ...interface{}) + Warningf(format string, args ...interface{}) + + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + +} \ No newline at end of file diff --git a/contextlogger_test.go b/logging_test.go similarity index 100% rename from contextlogger_test.go rename to logging_test.go diff --git a/logprinter.go b/logprinter.go new file mode 100644 index 0000000..f4d787c --- /dev/null +++ b/logprinter.go @@ -0,0 +1,25 @@ +package logging + +import ( + "log" + "io" +) + +// +// log using golang native logger solution +// +type gologPrinter struct { + log *log.Logger +} + +func(p *gologPrinter) Printf(format string, args ...interface{}) { + p.log.Printf(format, args...) +} + +func(p *gologPrinter) Print(args ...interface{}) { + p.log.Print(args...) +} + +func NewGologPrinter(out io.Writer, prefix string, flag int) *log.Logger { + return log.New(out, prefix, flag) +} \ No newline at end of file diff --git a/memory.go b/memory.go deleted file mode 100644 index 8d5152c..0000000 --- a/memory.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine - -package logging - -import ( - "sync" - "sync/atomic" - "time" - "unsafe" -) - -// TODO pick one of the memory backends and stick with it or share interface. - -// InitForTesting is a convenient method when using logging in a test. Once -// called, the time will be frozen to January 1, 1970 UTC. -func InitForTesting(level Level) *MemoryBackend { - Reset() - - memoryBackend := NewMemoryBackend(10240) - - leveledBackend := AddModuleLevel(memoryBackend) - leveledBackend.SetLevel(level, "") - SetBackend(leveledBackend) - - timeNow = func() time.Time { - return time.Unix(0, 0).UTC() - } - return memoryBackend -} - -// Node is a record node pointing to an optional next node. -type node struct { - next *node - Record *Record -} - -// Next returns the next record node. If there's no node available, it will -// return nil. -func (n *node) Next() *node { - return n.next -} - -// MemoryBackend is a simple memory based logging backend that will not produce -// any output but merly keep records, up to the given size, in memory. -type MemoryBackend struct { - size int32 - maxSize int32 - head, tail unsafe.Pointer -} - -// NewMemoryBackend creates a simple in-memory logging backend. -func NewMemoryBackend(size int) *MemoryBackend { - return &MemoryBackend{maxSize: int32(size)} -} - -// Log implements the Log method required by Backend. -func (b *MemoryBackend) Log(level Level, calldepth int, rec *Record) error { - var size int32 - - n := &node{Record: rec} - np := unsafe.Pointer(n) - - // Add the record to the tail. If there's no records available, tail and - // head will both be nil. When we successfully set the tail and the previous - // value was nil, it's safe to set the head to the current value too. - for { - tailp := b.tail - swapped := atomic.CompareAndSwapPointer( - &b.tail, - tailp, - np, - ) - if swapped == true { - if tailp == nil { - b.head = np - } else { - (*node)(tailp).next = n - } - size = atomic.AddInt32(&b.size, 1) - break - } - } - - // Since one record was added, we might have overflowed the list. Remove - // a record if that is the case. The size will fluctate a bit, but - // eventual consistent. - if b.maxSize > 0 && size > b.maxSize { - for { - headp := b.head - head := (*node)(b.head) - if head.next == nil { - break - } - swapped := atomic.CompareAndSwapPointer( - &b.head, - headp, - unsafe.Pointer(head.next), - ) - if swapped == true { - atomic.AddInt32(&b.size, -1) - break - } - } - } - return nil -} - -// Head returns the oldest record node kept in memory. It can be used to -// iterate over records, one by one, up to the last record. -// -// Note: new records can get added while iterating. Hence the number of records -// iterated over might be larger than the maximum size. -func (b *MemoryBackend) Head() *node { - return (*node)(b.head) -} - -type event int - -const ( - eventFlush event = iota - eventStop -) - -// ChannelMemoryBackend is very similar to the MemoryBackend, except that it -// internally utilizes a channel. -type ChannelMemoryBackend struct { - maxSize int - size int - incoming chan *Record - events chan event - mu sync.Mutex - running bool - flushWg sync.WaitGroup - stopWg sync.WaitGroup - head, tail *node -} - -// NewChannelMemoryBackend creates a simple in-memory logging backend which -// utilizes a go channel for communication. -// -// Start will automatically be called by this function. -func NewChannelMemoryBackend(size int) *ChannelMemoryBackend { - backend := &ChannelMemoryBackend{ - maxSize: size, - incoming: make(chan *Record, 1024), - events: make(chan event), - } - backend.Start() - return backend -} - -// Start launches the internal goroutine which starts processing data from the -// input channel. -func (b *ChannelMemoryBackend) Start() { - b.mu.Lock() - defer b.mu.Unlock() - - // Launch the goroutine unless it's already running. - if b.running != true { - b.running = true - b.stopWg.Add(1) - go b.process() - } -} - -func (b *ChannelMemoryBackend) process() { - defer b.stopWg.Done() - for { - select { - case rec := <-b.incoming: - b.insertRecord(rec) - case e := <-b.events: - switch e { - case eventStop: - return - case eventFlush: - for len(b.incoming) > 0 { - b.insertRecord(<-b.incoming) - } - b.flushWg.Done() - } - } - } -} - -func (b *ChannelMemoryBackend) insertRecord(rec *Record) { - prev := b.tail - b.tail = &node{Record: rec} - if prev == nil { - b.head = b.tail - } else { - prev.next = b.tail - } - - if b.maxSize > 0 && b.size >= b.maxSize { - b.head = b.head.next - } else { - b.size++ - } -} - -// Flush waits until all records in the buffered channel have been processed. -func (b *ChannelMemoryBackend) Flush() { - b.flushWg.Add(1) - b.events <- eventFlush - b.flushWg.Wait() -} - -// Stop signals the internal goroutine to exit and waits until it have. -func (b *ChannelMemoryBackend) Stop() { - b.mu.Lock() - if b.running == true { - b.running = false - b.events <- eventStop - } - b.mu.Unlock() - b.stopWg.Wait() -} - -// Log implements the Log method required by Backend. -func (b *ChannelMemoryBackend) Log(level Level, calldepth int, rec *Record) error { - b.incoming <- rec - return nil -} - -// Head returns the oldest record node kept in memory. It can be used to -// iterate over records, one by one, up to the last record. -// -// Note: new records can get added while iterating. Hence the number of records -// iterated over might be larger than the maximum size. -func (b *ChannelMemoryBackend) Head() *node { - return b.head -} diff --git a/memory_test.go b/memory_test.go deleted file mode 100644 index c2fe6c8..0000000 --- a/memory_test.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import ( - "strconv" - "testing" -) - -// TODO share more code between these tests -func MemoryRecordN(b *MemoryBackend, n int) *Record { - node := b.Head() - for i := 0; i < n; i++ { - if node == nil { - break - } - node = node.Next() - } - if node == nil { - return nil - } - return node.Record -} - -func ChannelMemoryRecordN(b *ChannelMemoryBackend, n int) *Record { - b.Flush() - node := b.Head() - for i := 0; i < n; i++ { - if node == nil { - break - } - node = node.Next() - } - if node == nil { - return nil - } - return node.Record -} - -func TestMemoryBackend(t *testing.T) { - backend := NewMemoryBackend(8) - SetBackend(backend) - - log := MustGetLogger("test") - - if nil != MemoryRecordN(backend, 0) || 0 != backend.size { - t.Errorf("memory level: %d", backend.size) - } - - // Run 13 times, the resulting vector should be [5..12] - for i := 0; i < 13; i++ { - log.Infof("%d", i) - } - - if 8 != backend.size { - t.Errorf("record length: %d", backend.size) - } - record := MemoryRecordN(backend, 0) - if "5" != record.Formatted(0) { - t.Errorf("unexpected start: %s", record.Formatted(0)) - } - for i := 0; i < 8; i++ { - record = MemoryRecordN(backend, i) - if strconv.Itoa(i+5) != record.Formatted(0) { - t.Errorf("unexpected record: %v", record.Formatted(0)) - } - } - record = MemoryRecordN(backend, 7) - if "12" != record.Formatted(0) { - t.Errorf("unexpected end: %s", record.Formatted(0)) - } - record = MemoryRecordN(backend, 8) - if nil != record { - t.Errorf("unexpected eof: %s", record.Formatted(0)) - } -} - -func TestChannelMemoryBackend(t *testing.T) { - backend := NewChannelMemoryBackend(8) - SetBackend(backend) - - log := MustGetLogger("test") - - if nil != ChannelMemoryRecordN(backend, 0) || 0 != backend.size { - t.Errorf("memory level: %d", backend.size) - } - - // Run 13 times, the resulting vector should be [5..12] - for i := 0; i < 13; i++ { - log.Infof("%d", i) - } - backend.Flush() - - if 8 != backend.size { - t.Errorf("record length: %d", backend.size) - } - record := ChannelMemoryRecordN(backend, 0) - if "5" != record.Formatted(0) { - t.Errorf("unexpected start: %s", record.Formatted(0)) - } - for i := 0; i < 8; i++ { - record = ChannelMemoryRecordN(backend, i) - if strconv.Itoa(i+5) != record.Formatted(0) { - t.Errorf("unexpected record: %v", record.Formatted(0)) - } - } - record = ChannelMemoryRecordN(backend, 7) - if "12" != record.Formatted(0) { - t.Errorf("unexpected end: %s", record.Formatted(0)) - } - record = ChannelMemoryRecordN(backend, 8) - if nil != record { - t.Errorf("unexpected eof: %s", record.Formatted(0)) - } -} diff --git a/multi.go b/multi.go deleted file mode 100644 index 3731653..0000000 --- a/multi.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -// TODO remove Level stuff from the multi logger. Do one thing. - -// multiLogger is a log multiplexer which can be used to utilize multiple log -// backends at once. -type multiLogger struct { - backends []LeveledBackend -} - -// MultiLogger creates a logger which contain multiple loggers. -func MultiLogger(backends ...Backend) LeveledBackend { - var leveledBackends []LeveledBackend - for _, backend := range backends { - leveledBackends = append(leveledBackends, AddModuleLevel(backend)) - } - return &multiLogger{leveledBackends} -} - -// Log passes the log record to all backends. -func (b *multiLogger) Log(level Level, calldepth int, rec *Record) (err error) { - for _, backend := range b.backends { - if backend.IsEnabledFor(level, rec.Module) { - // Shallow copy of the record for the formatted cache on Record and get the - // record formatter from the backend. - r2 := *rec - if e := backend.Log(level, calldepth+1, &r2); e != nil { - err = e - } - } - } - return -} - -// GetLevel returns the highest level enabled by all backends. -func (b *multiLogger) GetLevel(module string) Level { - var level Level - for _, backend := range b.backends { - if backendLevel := backend.GetLevel(module); backendLevel > level { - level = backendLevel - } - } - return level -} - -// SetLevel propagates the same level to all backends. -func (b *multiLogger) SetLevel(level Level, module string) { - for _, backend := range b.backends { - backend.SetLevel(level, module) - } -} - -// IsEnabledFor returns true if any of the backends are enabled for it. -func (b *multiLogger) IsEnabledFor(level Level, module string) bool { - for _, backend := range b.backends { - if backend.IsEnabledFor(level, module) { - return true - } - } - return false -} diff --git a/multi_test.go b/multi_test.go deleted file mode 100644 index e1da5e3..0000000 --- a/multi_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package logging - -import "testing" - -func TestMultiLogger(t *testing.T) { - log1 := NewMemoryBackend(8) - log2 := NewMemoryBackend(8) - SetBackend(MultiLogger(log1, log2)) - - log := MustGetLogger("test") - log.Debug("log") - - if "log" != MemoryRecordN(log1, 0).Formatted(0) { - t.Errorf("log1: %v", MemoryRecordN(log1, 0).Formatted(0)) - } - if "log" != MemoryRecordN(log2, 0).Formatted(0) { - t.Errorf("log2: %v", MemoryRecordN(log2, 0).Formatted(0)) - } -} - -func TestMultiLoggerLevel(t *testing.T) { - log1 := NewMemoryBackend(8) - log2 := NewMemoryBackend(8) - - leveled1 := AddModuleLevel(log1) - leveled2 := AddModuleLevel(log2) - - multi := MultiLogger(leveled1, leveled2) - multi.SetLevel(ERROR, "test") - SetBackend(multi) - - log := MustGetLogger("test") - log.Notice("log") - - if nil != MemoryRecordN(log1, 0) || nil != MemoryRecordN(log2, 0) { - t.Errorf("unexpected log record") - } - - leveled1.SetLevel(DEBUG, "test") - log.Notice("log") - if "log" != MemoryRecordN(log1, 0).Formatted(0) { - t.Errorf("log1 not received") - } - if nil != MemoryRecordN(log2, 0) { - t.Errorf("log2 received") - } -} diff --git a/contextlogger.go b/nativelogger.go similarity index 74% rename from contextlogger.go rename to nativelogger.go index 0e35a96..8374f33 100644 --- a/contextlogger.go +++ b/nativelogger.go @@ -2,50 +2,16 @@ package logging import ( "bytes" - "log" "io" ) -type Printer interface { - Printf(format string, args ...interface{}) - Print(args ...interface{}) -} - -type Log interface { - - Debug(args ...interface{}) - Debugf(format string, args ...interface{}) - - Info(args ...interface{}) - Infof(format string, args ...interface{}) - - Warning(args ...interface{}) - Warningf(format string, args ...interface{}) - - Error(args ...interface{}) - Errorf(format string, args ...interface{}) - -} - type nativeLogger struct { writer Printer } -type logPrinter struct { - log *log.Logger -} - func New(out io.Writer, prefix string, flag int) Log { - l := &nativeLogger{&logPrinter{log:log.New(out, prefix, flag)}} - return l; -} - -func(p *logPrinter) Printf(format string, args ...interface{}) { - p.log.Printf(format, args...) -} - -func(p *logPrinter) Print(args ...interface{}) { - p.log.Print(args...) + l := &nativeLogger{&gologPrinter{log:NewGologPrinter(out, prefix, flag)}} + return l; } func (l *nativeLogger) Debug(args ...interface{}) { @@ -102,4 +68,4 @@ func withLevel(buff *bytes.Buffer, lvl string) *bytes.Buffer { func withFormat(buff *bytes.Buffer, format string) *bytes.Buffer { buff.WriteString(format) return buff -} \ No newline at end of file +} diff --git a/syslog.go b/syslog.go deleted file mode 100644 index 4faa531..0000000 --- a/syslog.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//+build !windows,!plan9 - -package logging - -import "log/syslog" - -// SyslogBackend is a simple logger to syslog backend. It automatically maps -// the internal log levels to appropriate syslog log levels. -type SyslogBackend struct { - Writer *syslog.Writer -} - -// NewSyslogBackend connects to the syslog daemon using UNIX sockets with the -// given prefix. If prefix is not given, the prefix will be derived from the -// launched command. -func NewSyslogBackend(prefix string) (b *SyslogBackend, err error) { - var w *syslog.Writer - w, err = syslog.New(syslog.LOG_CRIT, prefix) - return &SyslogBackend{w}, err -} - -// NewSyslogBackendPriority is the same as NewSyslogBackend, but with custom -// syslog priority, like syslog.LOG_LOCAL3|syslog.LOG_DEBUG etc. -func NewSyslogBackendPriority(prefix string, priority syslog.Priority) (b *SyslogBackend, err error) { - var w *syslog.Writer - w, err = syslog.New(priority, prefix) - return &SyslogBackend{w}, err -} - -// Log implements the Backend interface. -func (b *SyslogBackend) Log(level Level, calldepth int, rec *Record) error { - line := rec.Formatted(calldepth + 1) - switch level { - case CRITICAL: - return b.Writer.Crit(line) - case ERROR: - return b.Writer.Err(line) - case WARNING: - return b.Writer.Warning(line) - case NOTICE: - return b.Writer.Notice(line) - case INFO: - return b.Writer.Info(line) - case DEBUG: - return b.Writer.Debug(line) - default: - } - panic("unhandled log level") -} diff --git a/syslog_fallback.go b/syslog_fallback.go deleted file mode 100644 index 91bc18d..0000000 --- a/syslog_fallback.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013, Örjan Persson. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//+build windows plan9 - -package logging - -import ( - "fmt" -) - -type Priority int - -type SyslogBackend struct { -} - -func NewSyslogBackend(prefix string) (b *SyslogBackend, err error) { - return nil, fmt.Errorf("Platform does not support syslog") -} - -func NewSyslogBackendPriority(prefix string, priority Priority) (b *SyslogBackend, err error) { - return nil, fmt.Errorf("Platform does not support syslog") -} - -func (b *SyslogBackend) Log(level Level, calldepth int, rec *Record) error { - return fmt.Errorf("Platform does not support syslog") -} From f3d0df099bc635039321373cfbb9281589ec672a Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 18:23:02 -0200 Subject: [PATCH 12/25] creating fliendly functions to create the log --- logprinter.go => gologprinter.go | 10 +++++++--- logging_test.go | 20 ++++++++++++-------- nativelogger.go | 6 ++---- 3 files changed, 21 insertions(+), 15 deletions(-) rename logprinter.go => gologprinter.go (60%) diff --git a/logprinter.go b/gologprinter.go similarity index 60% rename from logprinter.go rename to gologprinter.go index f4d787c..911dbef 100644 --- a/logprinter.go +++ b/gologprinter.go @@ -20,6 +20,10 @@ func(p *gologPrinter) Print(args ...interface{}) { p.log.Print(args...) } -func NewGologPrinter(out io.Writer, prefix string, flag int) *log.Logger { - return log.New(out, prefix, flag) -} \ No newline at end of file +func(p *gologPrinter) SetFlags(flags int){ + p.log.SetFlags(flags) +} + +func NewGologPrinter(out io.Writer, prefix string, flag int) *gologPrinter { + return &gologPrinter{log: log.New(out, prefix, flag)} +} diff --git a/logging_test.go b/logging_test.go index ccb8d17..cd07ad6 100644 --- a/logging_test.go +++ b/logging_test.go @@ -8,7 +8,7 @@ import ( func TestDebug(t *testing.T){ buff := new(bytes.Buffer) - logger := New(buff, "", 0) + logger := NewNoFlagInstance(buff) logger.Debug("name=", "elvis"); if actual := buff.String(); actual != "DEBUG m=TestDebug name=elvis\n" { @@ -19,7 +19,7 @@ func TestDebug(t *testing.T){ func TestDebugf(t *testing.T){ buff := new(bytes.Buffer) - logger := New(buff, "", 0) + logger := NewNoFlagInstance(buff) logger.Debugf("name=%v", "elvis"); if actual := buff.String(); actual != "DEBUG m=TestDebugf name=elvis\n" { @@ -30,7 +30,7 @@ func TestDebugf(t *testing.T){ func TestInfo(t *testing.T){ buff := new(bytes.Buffer) - logger := New(buff, "", 0) + logger := NewNoFlagInstance(buff) logger.Info("name=", "elvis"); if actual := buff.String(); actual != "INFO m=TestInfo name=elvis\n" { @@ -41,7 +41,7 @@ func TestInfo(t *testing.T){ func TestInfof(t *testing.T){ buff := new(bytes.Buffer) - logger := New(buff, "", 0) + logger := NewNoFlagInstance(buff) logger.Infof("name=%v", "elvis"); if actual := buff.String(); actual != "INFO m=TestInfof name=elvis\n" { @@ -52,7 +52,7 @@ func TestInfof(t *testing.T){ func TestWarn(t *testing.T){ buff := new(bytes.Buffer) - logger := New(buff, "", 0) + logger := NewNoFlagInstance(buff) logger.Warning("name=", "elvis"); if actual := buff.String(); actual != "WARNING m=TestWarn name=elvis\n" { @@ -63,7 +63,7 @@ func TestWarn(t *testing.T){ func TestWarnf(t *testing.T){ buff := new(bytes.Buffer) - logger := New(buff, "", 0) + logger := NewNoFlagInstance(buff) logger.Warningf("name=%v", "elvis"); if actual := buff.String(); actual != "WARNING m=TestWarnf name=elvis\n" { @@ -74,7 +74,7 @@ func TestWarnf(t *testing.T){ func TestError(t *testing.T){ buff := new(bytes.Buffer) - logger := New(buff, "", 0) + logger := NewNoFlagInstance(buff) logger.Error("name=", "elvis"); if actual := buff.String(); actual != "ERROR m=TestError name=elvis\n" { @@ -85,10 +85,14 @@ func TestError(t *testing.T){ func TestErrorf(t *testing.T){ buff := new(bytes.Buffer) - logger := New(buff, "", 0) + logger := NewNoFlagInstance(buff) logger.Errorf("name=%v", "elvis"); if actual := buff.String(); actual != "ERROR m=TestErrorf name=elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } + +func NewNoFlagInstance(buff *bytes.Buffer) Log { + return New(NewGologPrinter(buff, "", 0)); +} \ No newline at end of file diff --git a/nativelogger.go b/nativelogger.go index 8374f33..725e3b9 100644 --- a/nativelogger.go +++ b/nativelogger.go @@ -2,16 +2,14 @@ package logging import ( "bytes" - "io" ) type nativeLogger struct { writer Printer } -func New(out io.Writer, prefix string, flag int) Log { - l := &nativeLogger{&gologPrinter{log:NewGologPrinter(out, prefix, flag)}} - return l; +func New(p Printer) *nativeLogger { + return &nativeLogger{p} } func (l *nativeLogger) Debug(args ...interface{}) { From 57006a0f34687ae8c5e0f9d733ec125c7697e473 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 18:46:42 -0200 Subject: [PATCH 13/25] creating and testing static methods --- gologprinter.go | 4 ++ logging.go | 43 ++++++++++++++++++++ logging_test.go | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) diff --git a/gologprinter.go b/gologprinter.go index 911dbef..c6dd4ae 100644 --- a/gologprinter.go +++ b/gologprinter.go @@ -24,6 +24,10 @@ func(p *gologPrinter) SetFlags(flags int){ p.log.SetFlags(flags) } +func(p *gologPrinter) SetOutput(out io.Writer){ + p.log.SetOutput(out) +} + func NewGologPrinter(out io.Writer, prefix string, flag int) *gologPrinter { return &gologPrinter{log: log.New(out, prefix, flag)} } diff --git a/logging.go b/logging.go index fe4f2bb..9f022d8 100644 --- a/logging.go +++ b/logging.go @@ -3,6 +3,8 @@ package logging // // Who write the logs to output // +import "os" + type Printer interface { Printf(format string, args ...interface{}) Print(args ...interface{}) @@ -25,4 +27,45 @@ type Log interface { Error(args ...interface{}) Errorf(format string, args ...interface{}) +} + +var l Log = New(NewGologPrinter(os.Stdout, "", 0)) +func Debug(args ...interface{}) { + l.Debug(args) +} + +func Debugf(format string, args ...interface{}){ + l.Debugf(format, args) +} + +func Info(args ...interface{}){ + l.Info(args) +} + +func Infof(format string, args ...interface{}){ + l.Infof(format, args) +} + +func Warning(args ...interface{}){ + l.Warning( args) +} + +func Warningf(format string, args ...interface{}) { + l.Warningf(format, args) +} + +func Error(args ...interface{}){ + l.Error(args) +} + +func Errorf(format string, args ...interface{}){ + l.Errorf(format, args) +} + +func SetLog(logger Log){ + l = logger +} + +func GetLog() Log { + return l } \ No newline at end of file diff --git a/logging_test.go b/logging_test.go index cd07ad6..73e1e15 100644 --- a/logging_test.go +++ b/logging_test.go @@ -95,4 +95,110 @@ func TestErrorf(t *testing.T){ func NewNoFlagInstance(buff *bytes.Buffer) Log { return New(NewGologPrinter(buff, "", 0)); +} + +// +// static methods test +// +func TestStaticDebug(t *testing.T){ + + buff := new(bytes.Buffer) + logger := GetStaticLoggerAndDisableTimeLogging(buff) + logger.Debug("name=", "elvis"); + + expected := "DEBUG m=TestStaticDebug name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, expected='%q', actual='%q'", expected, actual) + } +} + +func TestStaticDebugf(t *testing.T){ + + buff := new(bytes.Buffer) + logger := GetStaticLoggerAndDisableTimeLogging(buff) + logger.Debugf("name=%v", "elvis"); + + expected := "DEBUG m=TestStaticDebugf name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, expected=%s, actual=%s", expected, actual) + } +} + +func TestStaticInfo(t *testing.T){ + + buff := new(bytes.Buffer) + logger := GetStaticLoggerAndDisableTimeLogging(buff) + logger.Info("name=", "elvis"); + + expected := "INFO m=TestStaticInfo name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) + } +} + +func TestStaticInfof(t *testing.T){ + + buff := new(bytes.Buffer) + logger := GetStaticLoggerAndDisableTimeLogging(buff) + logger.Infof("name=%v", "elvis"); + + expected := "INFO m=TestStaticInfof name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) + } +} + +func TestStaticWarn(t *testing.T){ + + buff := new(bytes.Buffer) + logger := GetStaticLoggerAndDisableTimeLogging(buff) + logger.Warning("name=", "elvis"); + + expected := "WARNING m=TestStaticWarn name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, expcted='%s', actual='%s'", expected, actual) + } +} + +func TestStaticWarnf(t *testing.T){ + + buff := new(bytes.Buffer) + logger := GetStaticLoggerAndDisableTimeLogging(buff) + logger.Warningf("name=%v", "elvis"); + + expected := "WARNING m=TestStaticWarnf name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) + } +} + +func TestStaticError(t *testing.T){ + + buff := new(bytes.Buffer) + logger := GetStaticLoggerAndDisableTimeLogging(buff) + logger.Error("name=", "elvis"); + + expected := "ERROR m=TestStaticError name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) + } +} + +func TestStaticErrorf(t *testing.T){ + + buff := new(bytes.Buffer) + logger := GetStaticLoggerAndDisableTimeLogging(buff) + logger.Errorf("name=%v", "elvis"); + + expected := "ERROR m=TestStaticErrorf name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, expected='%s', actual='%s'", buff.String(), actual) + } +} + +func GetStaticLoggerAndDisableTimeLogging(buff *bytes.Buffer) Log { + logger := GetLog().(*nativeLogger) + printer := logger.writer.(*gologPrinter) + printer.SetOutput(buff) + return logger } \ No newline at end of file From 63d65f4c5cac8bc94db64a24571b538e22cd56b4 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 19:08:20 -0200 Subject: [PATCH 14/25] adding examples --- gologprinter.go | 4 ++-- logging.go | 23 +++++++++++++---------- logging_test.go | 12 ++++++++++++ nativelogger.go | 8 ++++---- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/gologprinter.go b/gologprinter.go index c6dd4ae..c005012 100644 --- a/gologprinter.go +++ b/gologprinter.go @@ -16,8 +16,8 @@ func(p *gologPrinter) Printf(format string, args ...interface{}) { p.log.Printf(format, args...) } -func(p *gologPrinter) Print(args ...interface{}) { - p.log.Print(args...) +func(p *gologPrinter) Println(args ...interface{}) { + p.log.Println(args...) } func(p *gologPrinter) SetFlags(flags int){ diff --git a/logging.go b/logging.go index 9f022d8..24036c0 100644 --- a/logging.go +++ b/logging.go @@ -3,11 +3,14 @@ package logging // // Who write the logs to output // -import "os" +import ( + "os" + "log" +) type Printer interface { Printf(format string, args ...interface{}) - Print(args ...interface{}) + Println(args ...interface{}) } // @@ -29,37 +32,37 @@ type Log interface { } -var l Log = New(NewGologPrinter(os.Stdout, "", 0)) +var l Log = New(NewGologPrinter(os.Stdout, "", log.LstdFlags)) func Debug(args ...interface{}) { l.Debug(args) } func Debugf(format string, args ...interface{}){ - l.Debugf(format, args) + l.Debugf(format, args...) } func Info(args ...interface{}){ - l.Info(args) + l.Info(args...) } func Infof(format string, args ...interface{}){ - l.Infof(format, args) + l.Infof(format, args...) } func Warning(args ...interface{}){ - l.Warning( args) + l.Warning(args...) } func Warningf(format string, args ...interface{}) { - l.Warningf(format, args) + l.Warningf(format, args...) } func Error(args ...interface{}){ - l.Error(args) + l.Error(args...) } func Errorf(format string, args ...interface{}){ - l.Errorf(format, args) + l.Errorf(format, args...) } func SetLog(logger Log){ diff --git a/logging_test.go b/logging_test.go index 73e1e15..e9663f5 100644 --- a/logging_test.go +++ b/logging_test.go @@ -3,6 +3,7 @@ package logging import ( "testing" "bytes" + "os" ) func TestDebug(t *testing.T){ @@ -201,4 +202,15 @@ func GetStaticLoggerAndDisableTimeLogging(buff *bytes.Buffer) Log { printer := logger.writer.(*gologPrinter) printer.SetOutput(buff) return logger +} + +func ExampleDebugf() { + printer := GetLog().(*nativeLogger).writer.(*gologPrinter) + printer.SetFlags(0) + printer.SetOutput(os.Stdout) + + Debugf("name=%q, age=%d", "John\nZucky", 21) + + // Output: + // DEBUG m=Debugf name="John\nZucky", age=21 } \ No newline at end of file diff --git a/nativelogger.go b/nativelogger.go index 725e3b9..905ba9d 100644 --- a/nativelogger.go +++ b/nativelogger.go @@ -14,7 +14,7 @@ func New(p Printer) *nativeLogger { func (l *nativeLogger) Debug(args ...interface{}) { args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")).String()}, args...) - l.writer.Print(args...) + l.writer.Println(args...) } func (l *nativeLogger) Debugf(format string, args ...interface{}) { @@ -23,7 +23,7 @@ func (l *nativeLogger) Debugf(format string, args ...interface{}) { func (l *nativeLogger) Info(args ...interface{}) { args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "INFO")).String()}, args...) - l.writer.Print(args...) + l.writer.Println(args...) } func (l *nativeLogger) Infof(format string, args ...interface{}) { l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "INFO")), format).String(), args...) @@ -31,7 +31,7 @@ func (l *nativeLogger) Infof(format string, args ...interface{}) { func (l *nativeLogger) Warning(args ...interface{}) { args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "WARNING")).String()}, args...) - l.writer.Print(args...) + l.writer.Println(args...) } func (l *nativeLogger) Warningf(format string, args ...interface{}) { l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "WARNING")), format).String(), args...) @@ -39,7 +39,7 @@ func (l *nativeLogger) Warningf(format string, args ...interface{}) { func (l *nativeLogger) Error(args ...interface{}) { args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "ERROR")).String()}, args...) - l.writer.Print(args...) + l.writer.Println(args...) } func (l *nativeLogger) Errorf(format string, args ...interface{}) { l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "ERROR")), format).String(), args...) From 0ae26a7798675341fbf8f369d93057cdc99e258b Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 19:25:05 -0200 Subject: [PATCH 15/25] adding doc --- logging.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/logging.go b/logging.go index 24036c0..a41de17 100644 --- a/logging.go +++ b/logging.go @@ -65,10 +65,16 @@ func Errorf(format string, args ...interface{}){ l.Errorf(format, args...) } +// +// Change actual logger +// func SetLog(logger Log){ l = logger } +// +// Returns current logs +// func GetLog() Log { return l } \ No newline at end of file From f1b3141393c35a903a769781a50a1189d4396f07 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 19:32:48 -0200 Subject: [PATCH 16/25] adding printer to log interface and benchmark test --- logging.go | 8 ++++++++ logging_test.go | 13 ++++++++++--- nativelogger.go | 20 ++++++++++++-------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/logging.go b/logging.go index a41de17..041dade 100644 --- a/logging.go +++ b/logging.go @@ -6,11 +6,13 @@ package logging import ( "os" "log" + "io" ) type Printer interface { Printf(format string, args ...interface{}) Println(args ...interface{}) + SetOutput(w io.Writer) } // @@ -30,6 +32,8 @@ type Log interface { Error(args ...interface{}) Errorf(format string, args ...interface{}) + Printer() Printer + } var l Log = New(NewGologPrinter(os.Stdout, "", log.LstdFlags)) @@ -65,6 +69,10 @@ func Errorf(format string, args ...interface{}){ l.Errorf(format, args...) } +func SetOutput(w io.Writer) { + l.Printer().SetOutput(w) +} + // // Change actual logger // diff --git a/logging_test.go b/logging_test.go index e9663f5..3a1ac68 100644 --- a/logging_test.go +++ b/logging_test.go @@ -205,12 +205,19 @@ func GetStaticLoggerAndDisableTimeLogging(buff *bytes.Buffer) Log { } func ExampleDebugf() { - printer := GetLog().(*nativeLogger).writer.(*gologPrinter) - printer.SetFlags(0) + printer := GetLog().Printer().(*gologPrinter) printer.SetOutput(os.Stdout) - + printer.SetFlags(0) + Debugf("name=%q, age=%d", "John\nZucky", 21) // Output: // DEBUG m=Debugf name="John\nZucky", age=21 +} + +func BenchmarkDebugf(b *testing.B) { + GetLog().Printer().SetOutput(new(bytes.Buffer)) + for i:=0; i < b.N; i++ { + Debugf("i=%d", i) + } } \ No newline at end of file diff --git a/nativelogger.go b/nativelogger.go index 905ba9d..5f2ea3b 100644 --- a/nativelogger.go +++ b/nativelogger.go @@ -14,35 +14,39 @@ func New(p Printer) *nativeLogger { func (l *nativeLogger) Debug(args ...interface{}) { args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")).String()}, args...) - l.writer.Println(args...) + l.Printer().Println(args...) } func (l *nativeLogger) Debugf(format string, args ...interface{}) { - l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")), format).String(), args...) + l.Printer().Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "DEBUG")), format).String(), args...) } func (l *nativeLogger) Info(args ...interface{}) { args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "INFO")).String()}, args...) - l.writer.Println(args...) + l.Printer().Println(args...) } func (l *nativeLogger) Infof(format string, args ...interface{}) { - l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "INFO")), format).String(), args...) + l.Printer().Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "INFO")), format).String(), args...) } func (l *nativeLogger) Warning(args ...interface{}) { args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "WARNING")).String()}, args...) - l.writer.Println(args...) + l.Printer().Println(args...) } func (l *nativeLogger) Warningf(format string, args ...interface{}) { - l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "WARNING")), format).String(), args...) + l.Printer().Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "WARNING")), format).String(), args...) } func (l *nativeLogger) Error(args ...interface{}) { args = append([]interface{}{withCallerMethod(withLevel(new(bytes.Buffer), "ERROR")).String()}, args...) - l.writer.Println(args...) + l.Printer().Println(args...) } func (l *nativeLogger) Errorf(format string, args ...interface{}) { - l.writer.Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "ERROR")), format).String(), args...) + l.Printer().Printf(withFormat(withCallerMethod(withLevel(new(bytes.Buffer), "ERROR")), format).String(), args...) +} + +func (l *nativeLogger) Printer() Printer { + return l.writer } const level = 2 From cdc02888db8b8466c18112de911e586f5100da0c Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Thu, 19 Oct 2017 20:11:43 -0200 Subject: [PATCH 17/25] tests passing --- logging_test.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/logging_test.go b/logging_test.go index 3a1ac68..a53b691 100644 --- a/logging_test.go +++ b/logging_test.go @@ -4,6 +4,7 @@ import ( "testing" "bytes" "os" + "log" ) func TestDebug(t *testing.T){ @@ -12,7 +13,7 @@ func TestDebug(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Debug("name=", "elvis"); - if actual := buff.String(); actual != "DEBUG m=TestDebug name=elvis\n" { + if actual := buff.String(); actual != "DEBUG m=TestDebug name= elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } @@ -34,7 +35,7 @@ func TestInfo(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Info("name=", "elvis"); - if actual := buff.String(); actual != "INFO m=TestInfo name=elvis\n" { + if actual := buff.String(); actual != "INFO m=TestInfo name= elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } @@ -56,7 +57,7 @@ func TestWarn(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Warning("name=", "elvis"); - if actual := buff.String(); actual != "WARNING m=TestWarn name=elvis\n" { + if actual := buff.String(); actual != "WARNING m=TestWarn name= elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } @@ -78,7 +79,7 @@ func TestError(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Error("name=", "elvis"); - if actual := buff.String(); actual != "ERROR m=TestError name=elvis\n" { + if actual := buff.String(); actual != "ERROR m=TestError name= elvis\n" { t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) } } @@ -107,7 +108,7 @@ func TestStaticDebug(t *testing.T){ logger := GetStaticLoggerAndDisableTimeLogging(buff) logger.Debug("name=", "elvis"); - expected := "DEBUG m=TestStaticDebug name=elvis\n" + expected := "DEBUG m=TestStaticDebug name= elvis\n" if actual := buff.String(); actual != expected { t.Errorf("log format not expected, expected='%q', actual='%q'", expected, actual) } @@ -131,7 +132,7 @@ func TestStaticInfo(t *testing.T){ logger := GetStaticLoggerAndDisableTimeLogging(buff) logger.Info("name=", "elvis"); - expected := "INFO m=TestStaticInfo name=elvis\n" + expected := "INFO m=TestStaticInfo name= elvis\n" if actual := buff.String(); actual != expected { t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) } @@ -155,7 +156,7 @@ func TestStaticWarn(t *testing.T){ logger := GetStaticLoggerAndDisableTimeLogging(buff) logger.Warning("name=", "elvis"); - expected := "WARNING m=TestStaticWarn name=elvis\n" + expected := "WARNING m=TestStaticWarn name= elvis\n" if actual := buff.String(); actual != expected { t.Errorf("log format not expected, expcted='%s', actual='%s'", expected, actual) } @@ -179,7 +180,7 @@ func TestStaticError(t *testing.T){ logger := GetStaticLoggerAndDisableTimeLogging(buff) logger.Error("name=", "elvis"); - expected := "ERROR m=TestStaticError name=elvis\n" + expected := "ERROR m=TestStaticError name= elvis\n" if actual := buff.String(); actual != expected { t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) } @@ -198,8 +199,9 @@ func TestStaticErrorf(t *testing.T){ } func GetStaticLoggerAndDisableTimeLogging(buff *bytes.Buffer) Log { - logger := GetLog().(*nativeLogger) - printer := logger.writer.(*gologPrinter) + logger := GetLog() + printer := logger.Printer().(*gologPrinter) + printer.SetFlags(0) printer.SetOutput(buff) return logger } @@ -216,8 +218,16 @@ func ExampleDebugf() { } func BenchmarkDebugf(b *testing.B) { + + //go pprof.Lookup("block").WriteTo(os.Stdout, 2) + //f, err := os.Open("./cpu.prof") + //fmt.Println(err) + //pprof.StartCPUProfile(f) + //defer pprof.StopCPUProfile() GetLog().Printer().SetOutput(new(bytes.Buffer)) + log.SetOutput(new(bytes.Buffer)) for i:=0; i < b.N; i++ { Debugf("i=%d", i) + //log.Printf("i=%d", i) } } \ No newline at end of file From a367e851aee9a0b9eb88b143d1ef56a838ab0fad Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Fri, 20 Oct 2017 11:40:30 -0200 Subject: [PATCH 18/25] adding docker-compose --- .gitignore | 2 ++ docker-compose.yml | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index c38fa4e..bc17e08 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea *.iml +*.out +*.test diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..99643d1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: '2' +services: + go-logging: + container_name: go-logging + image: golang:1.9 + volumes: + - $PWD:/app/src/github.com/mageddo/go-logging + working_dir: /app/src/github.com/mageddo/go-logging + command: tail -f /dev/null From 9b14950d37869ed25a72ebcc70c890ab7650c401 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Fri, 20 Oct 2017 18:27:53 -0200 Subject: [PATCH 19/25] fixing test and docker compose --- docker-compose.yml | 4 +-- logging_test.go | 52 ++++++++++++++++++++-------------- nativelogger.go | 5 ++-- trace.go => pkg/trace/trace.go | 8 ++++-- 4 files changed, 40 insertions(+), 29 deletions(-) rename trace.go => pkg/trace/trace.go (83%) diff --git a/docker-compose.yml b/docker-compose.yml index 99643d1..035ea17 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,6 @@ services: container_name: go-logging image: golang:1.9 volumes: - - $PWD:/app/src/github.com/mageddo/go-logging - working_dir: /app/src/github.com/mageddo/go-logging + - $PWD:/go/src/github.com/mageddo/go-logging + working_dir: /go/src/github.com/mageddo/go-logging command: tail -f /dev/null diff --git a/logging_test.go b/logging_test.go index a53b691..c7fbb35 100644 --- a/logging_test.go +++ b/logging_test.go @@ -13,8 +13,9 @@ func TestDebug(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Debug("name=", "elvis"); - if actual := buff.String(); actual != "DEBUG m=TestDebug name= elvis\n" { - t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + expected := "DEBUG m=TestDebug name= elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, full=%s, actual=%s", expected, actual) } } @@ -24,8 +25,9 @@ func TestDebugf(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Debugf("name=%v", "elvis"); - if actual := buff.String(); actual != "DEBUG m=TestDebugf name=elvis\n" { - t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + expected := "DEBUG m=TestDebugf name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, full=%s, actual=%s", expected, actual) } } @@ -35,8 +37,9 @@ func TestInfo(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Info("name=", "elvis"); - if actual := buff.String(); actual != "INFO m=TestInfo name= elvis\n" { - t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + expected := "INFO m=TestInfo name= elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, full=%s, actual=%s", expected, actual) } } @@ -46,8 +49,9 @@ func TestInfof(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Infof("name=%v", "elvis"); - if actual := buff.String(); actual != "INFO m=TestInfof name=elvis\n" { - t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + expected := "INFO m=TestInfof name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, full=%s, actual=%s", expected, actual) } } @@ -57,8 +61,9 @@ func TestWarn(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Warning("name=", "elvis"); - if actual := buff.String(); actual != "WARNING m=TestWarn name= elvis\n" { - t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + expected := "WARNING m=TestWarn name= elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, full=%s, actual=%s", expected, actual) } } @@ -68,8 +73,9 @@ func TestWarnf(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Warningf("name=%v", "elvis"); - if actual := buff.String(); actual != "WARNING m=TestWarnf name=elvis\n" { - t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + expected := "WARNING m=TestWarnf name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, full=%s, actual=%s", expected, actual) } } @@ -79,8 +85,9 @@ func TestError(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Error("name=", "elvis"); - if actual := buff.String(); actual != "ERROR m=TestError name= elvis\n" { - t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + expected := "ERROR m=TestError name= elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, full=%s, actual=%s", expected, actual) } } @@ -90,8 +97,9 @@ func TestErrorf(t *testing.T){ logger := NewNoFlagInstance(buff) logger.Errorf("name=%v", "elvis"); - if actual := buff.String(); actual != "ERROR m=TestErrorf name=elvis\n" { - t.Errorf("log format not expected, full=%s, actual=%s", buff.String(), actual) + expected := "ERROR m=TestErrorf name=elvis\n" + if actual := buff.String(); actual != expected { + t.Errorf("log format not expected, full=%s, actual=%s", expected, actual) } } @@ -134,7 +142,7 @@ func TestStaticInfo(t *testing.T){ expected := "INFO m=TestStaticInfo name= elvis\n" if actual := buff.String(); actual != expected { - t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) + t.Errorf("log format not expected, expected='%q', actual='%q'", expected, actual) } } @@ -146,7 +154,7 @@ func TestStaticInfof(t *testing.T){ expected := "INFO m=TestStaticInfof name=elvis\n" if actual := buff.String(); actual != expected { - t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) + t.Errorf("log format not expected, expected='%q', actual='%q'", expected, actual) } } @@ -158,7 +166,7 @@ func TestStaticWarn(t *testing.T){ expected := "WARNING m=TestStaticWarn name= elvis\n" if actual := buff.String(); actual != expected { - t.Errorf("log format not expected, expcted='%s', actual='%s'", expected, actual) + t.Errorf("log format not expected, expcted='%q', actual='%q'", expected, actual) } } @@ -170,7 +178,7 @@ func TestStaticWarnf(t *testing.T){ expected := "WARNING m=TestStaticWarnf name=elvis\n" if actual := buff.String(); actual != expected { - t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) + t.Errorf("log format not expected, expected='%q', actual='%q'", expected, actual) } } @@ -182,7 +190,7 @@ func TestStaticError(t *testing.T){ expected := "ERROR m=TestStaticError name= elvis\n" if actual := buff.String(); actual != expected { - t.Errorf("log format not expected, expected='%s', actual='%s'", expected, actual) + t.Errorf("log format not expected, expected='%q', actual='%q'", expected, actual) } } @@ -194,7 +202,7 @@ func TestStaticErrorf(t *testing.T){ expected := "ERROR m=TestStaticErrorf name=elvis\n" if actual := buff.String(); actual != expected { - t.Errorf("log format not expected, expected='%s', actual='%s'", buff.String(), actual) + t.Errorf("log format not expected, expected='%q', actual='%q'", expected, actual) } } diff --git a/nativelogger.go b/nativelogger.go index 5f2ea3b..d966f42 100644 --- a/nativelogger.go +++ b/nativelogger.go @@ -2,6 +2,7 @@ package logging import ( "bytes" + "github.com/mageddo/go-logging/pkg/trace" ) type nativeLogger struct { @@ -49,12 +50,12 @@ func (l *nativeLogger) Printer() Printer { return l.writer } -const level = 2 +const level = 3 // add method caller name to message func withCallerMethod(buff *bytes.Buffer) *bytes.Buffer { buff.WriteString("m=") - buff.WriteString(GetCallerFunctionNameSkippingAnnonymous(level)) + buff.WriteString(trace.GetCallerFunctionNameSkippingAnnonymous(level)) buff.WriteString(" ") return buff; } diff --git a/trace.go b/pkg/trace/trace.go similarity index 83% rename from trace.go rename to pkg/trace/trace.go index a6c5f59..b392d88 100644 --- a/trace.go +++ b/pkg/trace/trace.go @@ -1,4 +1,4 @@ -package logging +package trace // returns full package and function name // 0 for the caller name, 1 for a up level, etc... @@ -30,8 +30,10 @@ func GetCallerFunctionName(backLevel int) string { } -// retorna o nome da funcao chamadora mas se for uma funcao anonima -// entao busca em um level acima +// give the name of functions in stack +// backlevel +// 0 - returns the direct caller name +// 1 - returns the second to last function caller name and go on func GetCallerFunctionNameSkippingAnnonymous(backlevel int) string { var name string = ""; From e7b7bae91a3b17850d96631804d2b24425ec37f9 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Fri, 20 Oct 2017 18:29:07 -0200 Subject: [PATCH 20/25] creating tests for the tracer --- pkg/trace/trace_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 pkg/trace/trace_test.go diff --git a/pkg/trace/trace_test.go b/pkg/trace/trace_test.go new file mode 100644 index 0000000..c315160 --- /dev/null +++ b/pkg/trace/trace_test.go @@ -0,0 +1,25 @@ +package trace + +import ( + "testing" +) + +func TestGetCallerFunctionNameSkippingAnnonymous(t *testing.T){ + + result := GetCallerFunctionNameSkippingAnnonymous(0) + expected := "TestGetCallerFunctionNameSkippingAnnonymous" + if result != expected { + t.Errorf("actual=%q, expected=%q", result, expected) + } +} + +func BenchmarkGetCallerFunctionNameSkippingAnnonymous(t *testing.B){ + + for i:=0; i < t.N; i++ { + result := GetCallerFunctionNameSkippingAnnonymous(0) + expected := "TestGetCallerFunctionNameSkippingAnnonymous" + if result != expected { + t.Errorf("actual=%q, expected=%q", result, expected) + } + } +} \ No newline at end of file From adea745af3519e46005428043d341a6af1cd0c18 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Fri, 20 Oct 2017 18:30:06 -0200 Subject: [PATCH 21/25] increasing tracer performance --- pkg/trace/trace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/trace/trace.go b/pkg/trace/trace.go index b392d88..5aa5922 100644 --- a/pkg/trace/trace.go +++ b/pkg/trace/trace.go @@ -34,13 +34,13 @@ func GetCallerFunctionName(backLevel int) string { // backlevel // 0 - returns the direct caller name // 1 - returns the second to last function caller name and go on +var rx, _ = regexp.Compile("^func\\d+") func GetCallerFunctionNameSkippingAnnonymous(backlevel int) string { var name string = ""; counter := 0 for tryAgain := true; tryAgain; counter++ { name = GetCallerFunctionName(backlevel + 1 + counter) - rx, _ := regexp.Compile("^func\\d+") tryAgain = rx.MatchString(name) } From f6e6c8db30ce96dfc2b8eec5b5b94a882c5531ec Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Fri, 20 Oct 2017 19:36:31 -0200 Subject: [PATCH 22/25] fixing lambda parent function name --- nativelogger.go | 2 +- pkg/trace/trace.go | 49 +++++++++++------------------------------ pkg/trace/trace_test.go | 22 ++++++++++++------ 3 files changed, 29 insertions(+), 44 deletions(-) diff --git a/nativelogger.go b/nativelogger.go index d966f42..e52f168 100644 --- a/nativelogger.go +++ b/nativelogger.go @@ -55,7 +55,7 @@ const level = 3 // add method caller name to message func withCallerMethod(buff *bytes.Buffer) *bytes.Buffer { buff.WriteString("m=") - buff.WriteString(trace.GetCallerFunctionNameSkippingAnnonymous(level)) + buff.WriteString(trace.GetCallerFunctionName(level)) buff.WriteString(" ") return buff; } diff --git a/pkg/trace/trace.go b/pkg/trace/trace.go index 5aa5922..3cae886 100644 --- a/pkg/trace/trace.go +++ b/pkg/trace/trace.go @@ -1,49 +1,26 @@ package trace -// returns full package and function name -// 0 for the caller name, 1 for a up level, etc... import ( "runtime" "strings" "regexp" ) -func GetCallerName(backLevel int) string { - - pc := make([]uintptr, 10) // at least 1 entry needed - runtime.Callers(backLevel + 2, pc) - f := runtime.FuncForPC(pc[0]) - return f.Name(); - -} - -// returns only function name +var rx, _ = regexp.Compile("\\.func\\d+$") func GetCallerFunctionName(backLevel int) string { - caller := GetCallerName(backLevel + 1) - sp := strings.Split(caller, ".") - if (len(sp) == 0) { - return "" + backLevel += 2 + var pc = make([]uintptr, backLevel + 3) + runtime.Callers(backLevel, pc) + tryAgain := true + var fn *runtime.Func + for i:=0; i < len(pc) && tryAgain; i++ { + fn = runtime.FuncForPC(pc[i]) + tryAgain = rx.MatchString(fn.Name()) + //log.Printf("for, tryAgain=%v, name=%s", tryAgain, fn.Name()) } - - return sp[len(sp) - 1] -} - - -// give the name of functions in stack -// backlevel -// 0 - returns the direct caller name -// 1 - returns the second to last function caller name and go on -var rx, _ = regexp.Compile("^func\\d+") -func GetCallerFunctionNameSkippingAnnonymous(backlevel int) string { - - var name string = ""; - counter := 0 - for tryAgain := true; tryAgain; counter++ { - name = GetCallerFunctionName(backlevel + 1 + counter) - tryAgain = rx.MatchString(name) + if sp := strings.Split(fn.Name(), "."); len(sp) != 0 { + return sp[len(sp) - 1] } - - return name - + return "" } \ No newline at end of file diff --git a/pkg/trace/trace_test.go b/pkg/trace/trace_test.go index c315160..f5b4d54 100644 --- a/pkg/trace/trace_test.go +++ b/pkg/trace/trace_test.go @@ -4,20 +4,28 @@ import ( "testing" ) -func TestGetCallerFunctionNameSkippingAnnonymous(t *testing.T){ - - result := GetCallerFunctionNameSkippingAnnonymous(0) - expected := "TestGetCallerFunctionNameSkippingAnnonymous" +func TestGetCallerFunctionName(t *testing.T){ + result := GetCallerFunctionName(0) + expected := "TestGetCallerFunctionName" if result != expected { t.Errorf("actual=%q, expected=%q", result, expected) } } -func BenchmarkGetCallerFunctionNameSkippingAnnonymous(t *testing.B){ +func TestGetCallerFunctionNameInsideLambda(t *testing.T) { + func(){ + result := GetCallerFunctionName(0) + expected := "TestGetCallerFunctionNameInsideLambda" + if result != expected { + t.Errorf("actual=%q, expected=%q", result, expected) + } + }() +} +func BenchmarkGetCallerFunctionName(t *testing.B){ for i:=0; i < t.N; i++ { - result := GetCallerFunctionNameSkippingAnnonymous(0) - expected := "TestGetCallerFunctionNameSkippingAnnonymous" + result := GetCallerFunctionName(0) + expected := "BenchmarkGetCallerFunctionName" if result != expected { t.Errorf("actual=%q, expected=%q", result, expected) } From 2abd6978b72f8caf5cb090329b112bdbe3756092 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Fri, 20 Oct 2017 19:41:45 -0200 Subject: [PATCH 23/25] increasing performance --- pkg/trace/trace.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pkg/trace/trace.go b/pkg/trace/trace.go index 3cae886..ac77e0f 100644 --- a/pkg/trace/trace.go +++ b/pkg/trace/trace.go @@ -10,17 +10,15 @@ var rx, _ = regexp.Compile("\\.func\\d+$") func GetCallerFunctionName(backLevel int) string { backLevel += 2 - var pc = make([]uintptr, backLevel + 3) + var pc, tryAgain = make([]uintptr, backLevel + 3), true runtime.Callers(backLevel, pc) - tryAgain := true var fn *runtime.Func for i:=0; i < len(pc) && tryAgain; i++ { fn = runtime.FuncForPC(pc[i]) tryAgain = rx.MatchString(fn.Name()) - //log.Printf("for, tryAgain=%v, name=%s", tryAgain, fn.Name()) } - if sp := strings.Split(fn.Name(), "."); len(sp) != 0 { - return sp[len(sp) - 1] + if index := strings.LastIndex(fn.Name(), "."); index != -1 { + return fn.Name()[index + 1:] } return "" } \ No newline at end of file From 3931328628e254e29ac0cd4d857babe7ecd499fe Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Fri, 20 Oct 2017 19:43:14 -0200 Subject: [PATCH 24/25] fixing level --- nativelogger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nativelogger.go b/nativelogger.go index e52f168..1cca0dc 100644 --- a/nativelogger.go +++ b/nativelogger.go @@ -50,7 +50,7 @@ func (l *nativeLogger) Printer() Printer { return l.writer } -const level = 3 +const level = 2 // add method caller name to message func withCallerMethod(buff *bytes.Buffer) *bytes.Buffer { From 29ad9bb52f97d86c64b5662cfc6011a626103b89 Mon Sep 17 00:00:00 2001 From: Elvis de Freitas Souza Date: Fri, 20 Oct 2017 19:44:33 -0200 Subject: [PATCH 25/25] documenting --- pkg/trace/trace.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/trace/trace.go b/pkg/trace/trace.go index ac77e0f..87e9a96 100644 --- a/pkg/trace/trace.go +++ b/pkg/trace/trace.go @@ -6,6 +6,13 @@ import ( "regexp" ) + +// +// Return the caller function name +// 0 -> returns the current caller function +// 1 -> returns the current caller parent +// etc. +// var rx, _ = regexp.Compile("\\.func\\d+$") func GetCallerFunctionName(backLevel int) string {