-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add an option to provide a custom logger (#8)
* feaT: add an option to provide a custom logger * update elfdump
- Loading branch information
1 parent
3eadc59
commit 33b33db
Showing
21 changed files
with
1,157 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Logger | ||
|
||
This code was taken from the go microservice framework [kratos](https://github.com/go-kratos/kratos). | ||
|
||
## Usage | ||
|
||
### Structured logging | ||
|
||
```go | ||
logger := log.NewStdLogger(os.Stdout) | ||
// fields & valuer | ||
logger = log.With(logger, | ||
"service.name", "hellworld", | ||
"service.version", "v1.0.0", | ||
"ts", log.DefaultTimestamp, | ||
"caller", log.DefaultCaller, | ||
) | ||
logger.Log(log.LevelInfo, "key", "value") | ||
|
||
// helper | ||
helper := log.NewHelper(logger) | ||
helper.Log(log.LevelInfo, "key", "value") | ||
helper.Info("info message") | ||
helper.Infof("info %s", "message") | ||
helper.Infow("key", "value") | ||
|
||
// filter | ||
log := log.NewHelper(log.NewFilter(logger, | ||
log.FilterLevel(log.LevelInfo), | ||
log.FilterKey("foo"), | ||
log.FilterValue("bar"), | ||
log.FilterFunc(customFilter), | ||
)) | ||
log.Debug("debug log") | ||
log.Info("info log") | ||
log.Warn("warn log") | ||
log.Error("warn log") | ||
``` | ||
|
||
## Third party log library | ||
|
||
If you need to implement a third party logging library like `zap`, have a look this [url](https://github.com/go-kratos/kratos/tree/main/contrib/log). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package log | ||
|
||
// FilterOption is filter option. | ||
type FilterOption func(*Filter) | ||
|
||
const fuzzyStr = "***" | ||
|
||
// FilterLevel with filter level. | ||
func FilterLevel(level Level) FilterOption { | ||
return func(opts *Filter) { | ||
opts.level = level | ||
} | ||
} | ||
|
||
// FilterKey with filter key. | ||
func FilterKey(key ...string) FilterOption { | ||
return func(o *Filter) { | ||
for _, v := range key { | ||
o.key[v] = struct{}{} | ||
} | ||
} | ||
} | ||
|
||
// FilterValue with filter value. | ||
func FilterValue(value ...string) FilterOption { | ||
return func(o *Filter) { | ||
for _, v := range value { | ||
o.value[v] = struct{}{} | ||
} | ||
} | ||
} | ||
|
||
// FilterFunc with filter func. | ||
func FilterFunc(f func(level Level, keyvals ...interface{}) bool) FilterOption { | ||
return func(o *Filter) { | ||
o.filter = f | ||
} | ||
} | ||
|
||
// Filter is a logger filter. | ||
type Filter struct { | ||
logger Logger | ||
level Level | ||
key map[interface{}]struct{} | ||
value map[interface{}]struct{} | ||
filter func(level Level, keyvals ...interface{}) bool | ||
} | ||
|
||
// NewFilter new a logger filter. | ||
func NewFilter(logger Logger, opts ...FilterOption) *Filter { | ||
options := Filter{ | ||
logger: logger, | ||
key: make(map[interface{}]struct{}), | ||
value: make(map[interface{}]struct{}), | ||
} | ||
for _, o := range opts { | ||
o(&options) | ||
} | ||
return &options | ||
} | ||
|
||
// Log Print log by level and keyvals. | ||
func (f *Filter) Log(level Level, keyvals ...interface{}) error { | ||
if level < f.level { | ||
return nil | ||
} | ||
// fkv is used to provide a slice to contains both logger.prefix and keyvals for filter | ||
var fkv []interface{} | ||
if l, ok := f.logger.(*logger); ok { | ||
if len(l.prefix) > 0 { | ||
fkv = make([]interface{}, 0, len(l.prefix)+len(keyvals)) | ||
fkv = append(fkv, l.prefix...) | ||
fkv = append(fkv, keyvals...) | ||
} | ||
} else { | ||
fkv = keyvals | ||
} | ||
if f.filter != nil && f.filter(level, fkv...) { | ||
return nil | ||
} | ||
if len(f.key) > 0 || len(f.value) > 0 { | ||
for i := 0; i < len(keyvals); i += 2 { | ||
v := i + 1 | ||
if v >= len(keyvals) { | ||
continue | ||
} | ||
if _, ok := f.key[keyvals[i]]; ok { | ||
keyvals[v] = fuzzyStr | ||
} | ||
if _, ok := f.value[keyvals[v]]; ok { | ||
keyvals[v] = fuzzyStr | ||
} | ||
} | ||
} | ||
return f.logger.Log(level, keyvals...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package log | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"testing" | ||
) | ||
|
||
func TestFilterAll(t *testing.T) { | ||
logger := With(DefaultLogger, "ts", DefaultTimestamp, "caller", DefaultCaller) | ||
log := NewHelper(NewFilter(logger, | ||
FilterLevel(LevelDebug), | ||
FilterKey("username"), | ||
FilterValue("hello"), | ||
FilterFunc(testFilterFunc), | ||
)) | ||
log.Log(LevelDebug, "msg", "test debug") | ||
log.Info("hello") | ||
log.Infow("password", "123456") | ||
log.Infow("username", "kratos") | ||
log.Warn("warn log") | ||
} | ||
|
||
func TestFilterLevel(t *testing.T) { | ||
logger := With(DefaultLogger, "ts", DefaultTimestamp, "caller", DefaultCaller) | ||
log := NewHelper(NewFilter(NewFilter(logger, FilterLevel(LevelWarn)))) | ||
log.Log(LevelDebug, "msg1", "te1st debug") | ||
log.Debug("test debug") | ||
log.Debugf("test %s", "debug") | ||
log.Debugw("log", "test debug") | ||
log.Warn("warn log") | ||
} | ||
|
||
func TestFilterCaller(t *testing.T) { | ||
logger := With(DefaultLogger, "ts", DefaultTimestamp, "caller", DefaultCaller) | ||
log := NewFilter(logger) | ||
_ = log.Log(LevelDebug, "msg1", "te1st debug") | ||
logHelper := NewHelper(NewFilter(logger)) | ||
logHelper.Log(LevelDebug, "msg1", "te1st debug") | ||
} | ||
|
||
func TestFilterKey(t *testing.T) { | ||
logger := With(DefaultLogger, "ts", DefaultTimestamp, "caller", DefaultCaller) | ||
log := NewHelper(NewFilter(logger, FilterKey("password"))) | ||
log.Debugw("password", "123456") | ||
} | ||
|
||
func TestFilterValue(t *testing.T) { | ||
logger := With(DefaultLogger, "ts", DefaultTimestamp, "caller", DefaultCaller) | ||
log := NewHelper(NewFilter(logger, FilterValue("debug"))) | ||
log.Debugf("test %s", "debug") | ||
} | ||
|
||
func TestFilterFunc(t *testing.T) { | ||
logger := With(DefaultLogger, "ts", DefaultTimestamp, "caller", DefaultCaller) | ||
log := NewHelper(NewFilter(logger, FilterFunc(testFilterFunc))) | ||
log.Debug("debug level") | ||
log.Infow("password", "123456") | ||
} | ||
|
||
func BenchmarkFilterKey(b *testing.B) { | ||
log := NewHelper(NewFilter(NewStdLogger(io.Discard), FilterKey("password"))) | ||
for i := 0; i < b.N; i++ { | ||
log.Infow("password", "123456") | ||
} | ||
} | ||
|
||
func BenchmarkFilterValue(b *testing.B) { | ||
log := NewHelper(NewFilter(NewStdLogger(io.Discard), FilterValue("password"))) | ||
for i := 0; i < b.N; i++ { | ||
log.Infow("password") | ||
} | ||
} | ||
|
||
func BenchmarkFilterFunc(b *testing.B) { | ||
log := NewHelper(NewFilter(NewStdLogger(io.Discard), FilterFunc(testFilterFunc))) | ||
for i := 0; i < b.N; i++ { | ||
log.Info("password", "123456") | ||
} | ||
} | ||
|
||
func testFilterFunc(level Level, keyvals ...interface{}) bool { | ||
if level == LevelWarn { | ||
return true | ||
} | ||
for i := 0; i < len(keyvals); i++ { | ||
if keyvals[i] == "password" { | ||
keyvals[i+1] = fuzzyStr | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func TestFilterFuncWitchLoggerPrefix(t *testing.T) { | ||
buf := new(bytes.Buffer) | ||
tests := []struct { | ||
logger Logger | ||
want string | ||
}{ | ||
{ | ||
logger: NewFilter(With(NewStdLogger(buf), "caller", "caller", "prefix", "whaterver"), FilterFunc(testFilterFuncWithLoggerPrefix)), | ||
want: "", | ||
}, | ||
{ | ||
logger: NewFilter(With(NewStdLogger(buf), "caller", "caller"), FilterFunc(testFilterFuncWithLoggerPrefix)), | ||
want: "INFO caller=caller msg=msg\n", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
err := tt.logger.Log(LevelInfo, "msg", "msg") | ||
if err != nil { | ||
t.Fatal("err should be nil") | ||
} | ||
got := buf.String() | ||
if got != tt.want { | ||
t.Fatalf("filter should catch prefix, want %s, got %s.", tt.want, got) | ||
} | ||
buf.Reset() | ||
} | ||
} | ||
|
||
func testFilterFuncWithLoggerPrefix(level Level, keyvals ...interface{}) bool { | ||
if level == LevelWarn { | ||
return true | ||
} | ||
for i := 0; i < len(keyvals); i += 2 { | ||
if keyvals[i] == "prefix" { | ||
return true | ||
} | ||
} | ||
return false | ||
} |
Oops, something went wrong.