From a229960218e9e35a8168da145b2e6e1cbf167b4d Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 20 Aug 2021 15:44:08 +0800 Subject: [PATCH] add context id feature for package gctx/glog --- os/gctx/gctx.go | 47 +++++++++++++++++++++++++++++- os/gctx/gctx_test.go | 51 +++++++++++++++++++++++++++++++++ os/glog/glog_logger.go | 31 +++++++++++--------- os/glog/glog_logger_config.go | 3 ++ os/glog/glog_z_unit_ctx_test.go | 11 +++++++ 5 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 os/gctx/gctx_test.go diff --git a/os/gctx/gctx.go b/os/gctx/gctx.go index e2fffb48a..9eb91f5e6 100644 --- a/os/gctx/gctx.go +++ b/os/gctx/gctx.go @@ -7,9 +7,54 @@ // Package gctx wraps context.Context and provides extra context features. package gctx -import "context" +import ( + "context" + "github.com/gogf/gf/util/guid" +) type ( Ctx = context.Context // Ctx is short name alias for context.Context. StrKey string // StrKey is a type for warps basic type string as context key. ) + +const ( + // CtxKey is custom tracing context key for context id. + // The context id a unique string for certain context. + CtxKey StrKey = "GoFrameCtxId" +) + +// New creates and returns a context which contains context id. +func New() context.Context { + return WithCtx(context.Background()) +} + +// WithCtx creates and returns a context containing context id upon given parent context `ctx`. +func WithCtx(ctx context.Context) context.Context { + return WithPrefix(ctx, "") +} + +// WithPrefix creates and returns a context containing context id upon given parent context `ctx`. +// The generated context id has custom prefix string specified by parameter `prefix`. +func WithPrefix(ctx context.Context, prefix string) context.Context { + return WithValue(ctx, prefix+getUniqueID()) +} + +// WithValue creates and returns a context containing context id upon given parent context `ctx`. +// The generated context id value is specified by parameter `value`. +func WithValue(ctx context.Context, value string) context.Context { + if value == "" { + return New() + } + return context.WithValue(ctx, CtxKey, value) +} + +// Value retrieves and returns the context id from context. +func Value(ctx context.Context) string { + s, _ := ctx.Value(CtxKey).(string) + return s +} + +// getUniqueID produces a global unique string. +func getUniqueID() string { + return guid.S() +} diff --git a/os/gctx/gctx_test.go b/os/gctx/gctx_test.go new file mode 100644 index 000000000..d190d5a7a --- /dev/null +++ b/os/gctx/gctx_test.go @@ -0,0 +1,51 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gctx_test + +import ( + "context" + "github.com/gogf/gf/os/gctx" + "github.com/gogf/gf/text/gstr" + "testing" + + "github.com/gogf/gf/test/gtest" +) + +func Test_New(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + ctx := gctx.New() + t.AssertNE(ctx, nil) + t.AssertNE(gctx.Value(ctx), "") + }) +} + +func Test_WithCtx(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + ctx := context.WithValue(context.TODO(), "TEST", 1) + ctx = gctx.WithCtx(ctx) + t.AssertNE(gctx.Value(ctx), "") + t.Assert(ctx.Value("TEST"), 1) + }) +} + +func Test_WithPrefix(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + ctx := context.WithValue(context.TODO(), "TEST", 1) + ctx = gctx.WithPrefix(ctx, "H-") + t.Assert(gstr.Contains(gctx.Value(ctx), "H-"), true) + t.Assert(ctx.Value("TEST"), 1) + }) +} + +func Test_WithValue(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + ctx := context.WithValue(context.TODO(), "TEST", 1) + ctx = gctx.WithValue(ctx, "123") + t.Assert(gctx.Value(ctx), "123") + t.Assert(ctx.Value("TEST"), 1) + }) +} diff --git a/os/glog/glog_logger.go b/os/glog/glog_logger.go index 33dca1bf9..28342804b 100644 --- a/os/glog/glog_logger.go +++ b/os/glog/glog_logger.go @@ -154,13 +154,17 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { if l.config.Flags&(F_FILE_LONG|F_FILE_SHORT|F_CALLER_FN) > 0 { callerFnName, path, line := gdebug.CallerWithFilter(pathFilterKey, l.config.StSkip) if l.config.Flags&F_CALLER_FN > 0 { - input.CallerFunc = fmt.Sprintf(`[%s]`, callerFnName) + if len(callerFnName) > 2 { + input.CallerFunc = fmt.Sprintf(`[%s]`, callerFnName) + } } - if l.config.Flags&F_FILE_LONG > 0 { - input.CallerPath = fmt.Sprintf(`%s:%d:`, path, line) - } - if l.config.Flags&F_FILE_SHORT > 0 { - input.CallerPath = fmt.Sprintf(`%s:%d:`, gfile.Basename(path), line) + if line >= 0 && len(path) > 1 { + if l.config.Flags&F_FILE_LONG > 0 { + input.CallerPath = fmt.Sprintf(`%s:%d:`, path, line) + } + if l.config.Flags&F_FILE_SHORT > 0 { + input.CallerPath = fmt.Sprintf(`%s:%d:`, gfile.Basename(path), line) + } } } // Prefix. @@ -173,26 +177,25 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { // Tracing values. spanCtx := trace.SpanContextFromContext(ctx) if traceId := spanCtx.TraceID(); traceId.IsValid() { - input.CtxStr = "{" + traceId.String() + "}" + input.CtxStr = traceId.String() } // Context values. if len(l.config.CtxKeys) > 0 { - ctxStr := "" for _, ctxKey := range l.config.CtxKeys { var ctxValue interface{} if ctxValue = ctx.Value(ctxKey); ctxValue == nil { ctxValue = ctx.Value(gctx.StrKey(gconv.String(ctxKey))) } if ctxValue != nil { - if ctxStr != "" { - ctxStr += ", " + if input.CtxStr != "" { + input.CtxStr += ", " } - ctxStr += gconv.String(ctxValue) + input.CtxStr += gconv.String(ctxValue) } } - if ctxStr != "" { - input.CtxStr += "{" + ctxStr + "}" - } + } + if input.CtxStr != "" { + input.CtxStr = "{" + input.CtxStr + "}" } } var tempStr string diff --git a/os/glog/glog_logger_config.go b/os/glog/glog_logger_config.go index 81dce4604..1ed493531 100644 --- a/os/glog/glog_logger_config.go +++ b/os/glog/glog_logger_config.go @@ -7,6 +7,7 @@ package glog import ( + "github.com/gogf/gf/os/gctx" "io" "strings" "time" @@ -49,6 +50,7 @@ func DefaultConfig() Config { File: defaultFileFormat, Flags: F_TIME_STD, Level: LEVEL_ALL, + CtxKeys: []interface{}{gctx.CtxKey}, StStatus: 1, HeaderPrint: true, StdoutPrint: true, @@ -163,6 +165,7 @@ func (l *Logger) SetStackFilter(filter string) { // Note that multiple calls of this function will overwrite the previous set context keys. func (l *Logger) SetCtxKeys(keys ...interface{}) { l.config.CtxKeys = keys + l.config.CtxKeys = append(l.config.CtxKeys, gctx.CtxKey) } // AppendCtxKeys appends extra keys to logger. diff --git a/os/glog/glog_z_unit_ctx_test.go b/os/glog/glog_z_unit_ctx_test.go index e56fe59fe..e6811df72 100644 --- a/os/glog/glog_z_unit_ctx_test.go +++ b/os/glog/glog_z_unit_ctx_test.go @@ -10,6 +10,7 @@ import ( "bytes" "context" "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" "github.com/gogf/gf/os/glog" "github.com/gogf/gf/test/gtest" "github.com/gogf/gf/text/gstr" @@ -49,3 +50,13 @@ func Test_Ctx_Config(t *testing.T) { t.Assert(gstr.Count(w.String(), "1 2 3"), 1) }) } + +func Test_Ctx_CtxKey(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + w := bytes.NewBuffer(nil) + l := glog.NewWithWriter(w) + l.Ctx(gctx.WithValue(context.TODO(), "abcdefg")).Print(1, 2, 3) + t.Assert(gstr.Count(w.String(), "abcdefg"), 1) + t.Assert(gstr.Count(w.String(), "1 2 3"), 1) + }) +}