From 7570ade82a0536a0180f9d65cdb35148774f1764 Mon Sep 17 00:00:00 2001 From: andrey Date: Mon, 14 Mar 2022 09:58:23 +0300 Subject: [PATCH] upddate caller write method (#5) Co-authored-by: andrey1s Reviewed-on: https://gitoa.ru/go-4devs/log/pulls/5 Co-authored-by: andrey Co-committed-by: andrey --- LICENSE | 2 +- entry/caller.go | 2 +- entry/entry.go | 42 +++++++++++-- logger.go | 114 ++++++++++++++++------------------ logger_example_caller_test.go | 2 + 5 files changed, 92 insertions(+), 70 deletions(-) diff --git a/LICENSE b/LICENSE index 0dcfb43..00c2562 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -MIT License Copyright (c) 2020 go-4devs +MIT License Copyright (c) 2020-2022 4devs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/entry/caller.go b/entry/caller.go index 532c276..deaba93 100644 --- a/entry/caller.go +++ b/entry/caller.go @@ -7,7 +7,7 @@ import ( ) func Caller(depth int, full bool) string { - const offset = 4 + const offset = 3 _, file, line, has := runtime.Caller(depth + offset) if !has { diff --git a/entry/entry.go b/entry/entry.go index 32cbf93..edc9ff0 100644 --- a/entry/entry.go +++ b/entry/entry.go @@ -1,6 +1,7 @@ package entry import ( + "fmt" "strings" "gitoa.ru/go-4devs/log/field" @@ -27,7 +28,14 @@ func WithFields(fields ...field.Field) Option { func WithMessage(msg string) Option { return func(e *Entry) { - e.msg = msg + e.format = msg + } +} + +func WithMessagef(format string, args ...interface{}) Option { + return func(e *Entry) { + e.format = format + e.args = args } } @@ -41,7 +49,8 @@ func New(opts ...Option) *Entry { entry := &Entry{ fields: make(field.Fields, 0, defaultCap+1), level: level.Debug, - msg: "", + format: "", + args: make([]interface{}, 0, defaultCap+1), } for _, opt := range opts { @@ -53,13 +62,16 @@ func New(opts ...Option) *Entry { // Entry slice field. type Entry struct { - msg string + format string + args []interface{} level level.Level fields field.Fields } func (e *Entry) Reset() { e.fields = e.fields[:0] + e.args = e.args[:0] + e.format = "" } func (e *Entry) Fields() field.Fields { @@ -73,7 +85,7 @@ func (e *Entry) String() string { } str := make([]string, len(e.fields)+1) - str[0] = e.msg + str[0] = e.Message() for i, field := range e.fields { str[i+1] = field.String() @@ -83,7 +95,14 @@ func (e *Entry) String() string { } func (e *Entry) Message() string { - return e.msg + switch { + case len(e.args) > 0 && e.format != "": + return fmt.Sprintf(e.format, e.args...) + case len(e.args) > 0: + return fmt.Sprint(e.args...) + default: + return e.format + } } func (e *Entry) Level() level.Level { @@ -109,7 +128,18 @@ func (e *Entry) SetMessage(msg string) *Entry { return New().SetMessage(msg) } - e.msg = msg + e.format = msg + + return e +} + +func (e *Entry) SetMessagef(format string, args ...interface{}) *Entry { + if e == nil { + return New().SetMessagef(format, args...) + } + + e.format = format + e.args = append(e.args[:0], args...) return e } diff --git a/logger.go b/logger.go index b714ac2..64ea93c 100644 --- a/logger.go +++ b/logger.go @@ -28,38 +28,28 @@ func writeOutput(_ int, err error) { // Logger logged message. type Logger func(ctx context.Context, entry *entry.Entry) (int, error) -func (l Logger) log(ctx context.Context, level level.Level, args ...interface{}) { - writeOutput(l.write(ctx, level, fmt.Sprint(args...))) -} - func (l Logger) Write(in []byte) (int, error) { return l.write(context.Background(), level.Info, string(in)) } func (l Logger) write(ctx context.Context, level level.Level, msg string, fields ...field.Field) (int, error) { - writeEntry := entry.Get() + data := entry.Get() defer func() { - entry.Put(writeEntry) + entry.Put(data) }() - return l(ctx, writeEntry.SetLevel(level).SetMessage(msg).Add(fields...)) -} - -func (l Logger) logKVs(ctx context.Context, level level.Level, msg string, args ...interface{}) { - writeOutput(l.write(ctx, level, msg, l.kv(ctx, args...)...)) + return l(ctx, data.SetLevel(level).SetMessage(msg).Add(fields...)) } -func (l Logger) logKV(ctx context.Context, level level.Level, msg string, fields ...field.Field) { - writeOutput(l.write(ctx, level, msg, fields...)) -} +func (l Logger) writef(ctx context.Context, level level.Level, format string, args ...interface{}) (int, error) { + data := entry.Get() -func (l Logger) logf(ctx context.Context, level level.Level, format string, args ...interface{}) { - writeOutput(l.write(ctx, level, fmt.Sprintf(format, args...))) -} + defer func() { + entry.Put(data) + }() -func (l Logger) logln(ctx context.Context, level level.Level, args ...interface{}) { - writeOutput(l.write(ctx, level, fmt.Sprintln(args...))) + return l(ctx, data.SetLevel(level).SetMessagef(format, args...)) } func (l Logger) kv(ctx context.Context, args ...interface{}) field.Fields { @@ -77,7 +67,7 @@ func (l Logger) kv(ctx context.Context, args ...interface{}) field.Fields { } if i == len(args)-1 { - l.logKV(ctx, level.Critical, fmt.Sprint("Ignored key without a value.", args[i]), kvEntry.Fields()...) + writeOutput(l.write(ctx, level.Critical, fmt.Sprint("Ignored key without a value.", args[i]), kvEntry.Fields()...)) break } @@ -91,7 +81,7 @@ func (l Logger) kv(ctx context.Context, args ...interface{}) field.Fields { continue } - l.logKV(ctx, level.Critical, fmt.Sprint("Ignored key-value pairs with non-string keys.", key, val), kvEntry.Fields()...) + writeOutput(l.write(ctx, level.Critical, fmt.Sprint("Ignored key-value pairs with non-string keys.", key, val), kvEntry.Fields()...)) } return kvEntry.Fields() @@ -104,207 +94,207 @@ func (l Logger) With(mw ...Middleware) Logger { // Emerg log by emergency level. func (l Logger) Emerg(ctx context.Context, args ...interface{}) { - l.log(ctx, level.Emergency, args...) + writeOutput(l.writef(ctx, level.Emergency, "", args...)) } // Alert log by alert level. func (l Logger) Alert(ctx context.Context, args ...interface{}) { - l.log(ctx, level.Alert, args...) + writeOutput(l.writef(ctx, level.Alert, "", args...)) } // Crit log by critical level. func (l Logger) Crit(ctx context.Context, args ...interface{}) { - l.log(ctx, level.Critical, args...) + writeOutput(l.writef(ctx, level.Critical, "", args...)) } // Err log by error level. func (l Logger) Err(ctx context.Context, args ...interface{}) { - l.log(ctx, level.Error, args...) + writeOutput(l.writef(ctx, level.Error, "", args...)) } // Warn log by warning level. func (l Logger) Warn(ctx context.Context, args ...interface{}) { - l.log(ctx, level.Warning, args...) + writeOutput(l.writef(ctx, level.Warning, "", args...)) } // Notice log by notice level. func (l Logger) Notice(ctx context.Context, args ...interface{}) { - l.log(ctx, level.Notice, args...) + writeOutput(l.writef(ctx, level.Notice, "", args...)) } // Info log by info level. func (l Logger) Info(ctx context.Context, args ...interface{}) { - l.log(ctx, level.Info, args...) + writeOutput(l.writef(ctx, level.Info, "", args...)) } // Debug log by debug level. func (l Logger) Debug(ctx context.Context, args ...interface{}) { - l.log(ctx, level.Debug, args...) + writeOutput(l.writef(ctx, level.Debug, "", args...)) } // Print log by info level and arguments. func (l Logger) Print(args ...interface{}) { - l.log(context.Background(), level.Info, args...) + writeOutput(l.writef(context.Background(), level.Info, "", args...)) } // Fatal log by alert level and arguments. func (l Logger) Fatal(args ...interface{}) { - l.log(context.Background(), level.Alert, args...) + writeOutput(l.writef(context.Background(), level.Alert, "", args...)) } // Panic log by emergency level and arguments. func (l Logger) Panic(args ...interface{}) { - l.log(context.Background(), level.Emergency, args...) + writeOutput(l.writef(context.Background(), level.Emergency, "", args...)) } // Println log by info level and arguments. func (l Logger) Println(args ...interface{}) { - l.logln(context.Background(), level.Info, args...) + writeOutput(l.write(context.Background(), level.Info, fmt.Sprintln(args...))) } // Fatalln log by alert level and arguments. func (l Logger) Fatalln(args ...interface{}) { - l.logln(context.Background(), level.Alert, args...) + writeOutput(l.write(context.Background(), level.Alert, fmt.Sprintln(args...))) } // Panicln log by emergency level and arguments. func (l Logger) Panicln(args ...interface{}) { - l.logln(context.Background(), level.Emergency, args...) + writeOutput(l.write(context.Background(), level.Emergency, fmt.Sprintln(args...))) } // EmergKVs sugared log by emergency level and key-values. func (l Logger) EmergKVs(ctx context.Context, msg string, args ...interface{}) { - l.logKVs(ctx, level.Emergency, msg, args...) + writeOutput(l.write(ctx, level.Emergency, msg, l.kv(ctx, args...)...)) } // AlertKVs sugared log by alert level and key-values. func (l Logger) AlertKVs(ctx context.Context, msg string, args ...interface{}) { - l.logKVs(ctx, level.Alert, msg, args...) + writeOutput(l.write(ctx, level.Alert, msg, l.kv(ctx, args...)...)) } // CritKVs sugared log by critcal level and key-values. func (l Logger) CritKVs(ctx context.Context, msg string, args ...interface{}) { - l.logKVs(ctx, level.Critical, msg, args...) + writeOutput(l.write(ctx, level.Critical, msg, l.kv(ctx, args...)...)) } // ErrKVs sugared log by error level and key-values. func (l Logger) ErrKVs(ctx context.Context, msg string, args ...interface{}) { - l.logKVs(ctx, level.Error, msg, args...) + writeOutput(l.write(ctx, level.Error, msg, l.kv(ctx, args...)...)) } // WarnKVs sugared log by warning level and key-values. func (l Logger) WarnKVs(ctx context.Context, msg string, args ...interface{}) { - l.logKVs(ctx, level.Warning, msg, args...) + writeOutput(l.write(ctx, level.Warning, msg, l.kv(ctx, args...)...)) } // NoticeKVs sugared log by notice level and key-values. func (l Logger) NoticeKVs(ctx context.Context, msg string, args ...interface{}) { - l.logKVs(ctx, level.Notice, msg, args...) + writeOutput(l.write(ctx, level.Notice, msg, l.kv(ctx, args...)...)) } // InfoKVs sugared log by info level and key-values. func (l Logger) InfoKVs(ctx context.Context, msg string, args ...interface{}) { - l.logKVs(ctx, level.Info, msg, args...) + writeOutput(l.write(ctx, level.Info, msg, l.kv(ctx, args...)...)) } // DebugKVs sugared log by debug level and key-values. func (l Logger) DebugKVs(ctx context.Context, msg string, args ...interface{}) { - l.logKVs(ctx, level.Debug, msg, args...) + writeOutput(l.write(ctx, level.Debug, msg, l.kv(ctx, args...)...)) } // EmergKV log by emergency level and key-values. func (l Logger) EmergKV(ctx context.Context, msg string, args ...field.Field) { - l.logKV(ctx, level.Emergency, msg, args...) + writeOutput(l.write(ctx, level.Emergency, msg, args...)) } // AlertKV log by alert level and key-values. func (l Logger) AlertKV(ctx context.Context, msg string, args ...field.Field) { - l.logKV(ctx, level.Alert, msg, args...) + writeOutput(l.write(ctx, level.Alert, msg, args...)) } // CritKV log by critcal level and key-values. func (l Logger) CritKV(ctx context.Context, msg string, args ...field.Field) { - l.logKV(ctx, level.Critical, msg, args...) + writeOutput(l.write(ctx, level.Critical, msg, args...)) } // ErrKV log by error level and key-values. func (l Logger) ErrKV(ctx context.Context, msg string, args ...field.Field) { - l.logKV(ctx, level.Error, msg, args...) + writeOutput(l.write(ctx, level.Error, msg, args...)) } // WarnKV log by warning level and key-values. func (l Logger) WarnKV(ctx context.Context, msg string, args ...field.Field) { - l.logKV(ctx, level.Warning, msg, args...) + writeOutput(l.write(ctx, level.Warning, msg, args...)) } // NoticeKV log by notice level and key-values. func (l Logger) NoticeKV(ctx context.Context, msg string, args ...field.Field) { - l.logKV(ctx, level.Notice, msg, args...) + writeOutput(l.write(ctx, level.Notice, msg, args...)) } // InfoKV log by info level and key-values. func (l Logger) InfoKV(ctx context.Context, msg string, args ...field.Field) { - l.logKV(ctx, level.Info, msg, args...) + writeOutput(l.write(ctx, level.Info, msg, args...)) } // DebugKV log by debug level and key-values. func (l Logger) DebugKV(ctx context.Context, msg string, args ...field.Field) { - l.logKV(ctx, level.Debug, msg, args...) + writeOutput(l.write(ctx, level.Debug, msg, args...)) } // Emergf log by emergency level by format and arguments. func (l Logger) Emergf(ctx context.Context, format string, args ...interface{}) { - l.logf(ctx, level.Emergency, format, args...) + writeOutput(l.writef(ctx, level.Emergency, format, args...)) } // Alertf log by alert level by format and arguments. func (l Logger) Alertf(ctx context.Context, format string, args ...interface{}) { - l.logf(ctx, level.Alert, format, args...) + writeOutput(l.writef(ctx, level.Alert, format, args...)) } // Critf log by critical level by format and arguments. func (l Logger) Critf(ctx context.Context, format string, args ...interface{}) { - l.logf(ctx, level.Critical, format, args...) + writeOutput(l.writef(ctx, level.Critical, format, args...)) } // Errf log by error level by format and arguments. func (l Logger) Errf(ctx context.Context, format string, args ...interface{}) { - l.logf(ctx, level.Error, format, args...) + writeOutput(l.writef(ctx, level.Error, format, args...)) } // Warnf log by warning level by format and arguments. func (l Logger) Warnf(ctx context.Context, format string, args ...interface{}) { - l.logf(ctx, level.Warning, format, args...) + writeOutput(l.writef(ctx, level.Warning, format, args...)) } // Noticef log by notice level by format and arguments. func (l Logger) Noticef(ctx context.Context, format string, args ...interface{}) { - l.logf(ctx, level.Notice, format, args...) + writeOutput(l.writef(ctx, level.Notice, format, args...)) } // Infof log by info level by format and arguments. func (l Logger) Infof(ctx context.Context, format string, args ...interface{}) { - l.logf(ctx, level.Info, format, args...) + writeOutput(l.writef(ctx, level.Info, format, args...)) } // Debugf log by debug level by format and arguments. func (l Logger) Debugf(ctx context.Context, format string, args ...interface{}) { - l.logf(ctx, level.Debug, format, args...) + writeOutput(l.writef(ctx, level.Debug, format, args...)) } // Printf log by info level by format and arguments without context. func (l Logger) Printf(format string, args ...interface{}) { - l.logf(context.Background(), level.Info, format, args...) + writeOutput(l.writef(context.Background(), level.Info, format, args...)) } // Fatalf log by alert level by format and arguments without context. func (l Logger) Fatalf(format string, args ...interface{}) { - l.logf(context.Background(), level.Alert, format, args...) + writeOutput(l.writef(context.Background(), level.Alert, format, args...)) } // Panicf log by emergency level and arguments without context. func (l Logger) Panicf(format string, args ...interface{}) { - l.logf(context.Background(), level.Emergency, format, args...) + writeOutput(l.writef(context.Background(), level.Emergency, format, args...)) } func (l Logger) Writer(ctx context.Context, level level.Level, fields ...field.Field) io.Writer { diff --git a/logger_example_caller_test.go b/logger_example_caller_test.go index 49e99f3..3901f08 100644 --- a/logger_example_caller_test.go +++ b/logger_example_caller_test.go @@ -13,8 +13,10 @@ func ExampleNew_withCaller() { ) logger.Err(ctx, "same error message") logger.InfoKVs(ctx, "same info message", "api-version", 0.1) + _, _ = logger.Write([]byte("same write message")) // Output: // msg="same error message" level=error caller=logger_example_caller_test.go:14 // msg="same info message" api-version=0.1 level=info caller=logger_example_caller_test.go:15 + // msg="same write message" level=info caller=logger_example_caller_test.go:16 }