From 1cb79afdccdbafe09246c9c7c1d84e7158b9ed1c Mon Sep 17 00:00:00 2001 From: jslching <38669839+jslching@users.noreply.github.com> Date: Fri, 3 Nov 2023 13:21:57 -0400 Subject: [PATCH 1/2] add debug log for context stack --- util/ctxutil/stack.go | 94 +++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/util/ctxutil/stack.go b/util/ctxutil/stack.go index bd27a6f..0911569 100644 --- a/util/ctxutil/stack.go +++ b/util/ctxutil/stack.go @@ -5,6 +5,7 @@ import ( "encoding/json" "runtime/debug" "sync" + "time" "github.com/eluv-io/common-go/util/goutil" "github.com/eluv-io/common-go/util/traceutil/trace" @@ -12,7 +13,31 @@ import ( // NewStack creates a new ContextStack. func NewStack() ContextStack { - return &contextStack{stacks: map[int64]*entry{}} + c := &contextStack{stacks: map[int64]*entry{}} + go func() { + for { + // Log stack info every 5 min for debugging + time.Sleep(time.Minute * 5) + c.mutex.Lock() + size := len(c.stacks) + depths := map[int64]int{} + for gid, entry := range c.stacks { + depths[gid] = stackDepth(entry.stack) + } + c.mutex.Unlock() + log.Warn("ContextStack", "size", size, "depths", depths) + } + }() + return c +} + +func stackDepth(s *stack) int { + depth := 1 + for s.parent != nil { + s = s.parent + depth++ + } + return depth } // ContextStack provides access to a stack of context.Context values individually managed per goroutine. It is @@ -20,48 +45,49 @@ func NewStack() ContextStack { // call chain. // // The "standard" way of using contexts in go is passing it to each function in a call chain: -// type anObject struct {} // -// func (r *anObject) A(ctx context.Context) { -// ctx = context.WithValue(context.Background(), "key", "val") -// r.B(ctx) -// ... -// } +// type anObject struct {} +// +// func (r *anObject) A(ctx context.Context) { +// ctx = context.WithValue(context.Background(), "key", "val") +// r.B(ctx) +// ... +// } // -// func (r *anObject) B(ctx context.Context) { -// ... -// r.C(ctx) -// ... -// } +// func (r *anObject) B(ctx context.Context) { +// ... +// r.C(ctx) +// ... +// } // -// func (r *anObject) C(ctx context.Context) string { -// val := ctx.Value("key") -// ... -// } +// func (r *anObject) C(ctx context.Context) string { +// val := ctx.Value("key") +// ... +// } // // ContextStack achieves the same without adding a context to each method call: // -// type anObject struct { -// cs *ctxutil.ContextStack -// } +// type anObject struct { +// cs *ctxutil.ContextStack +// } // -// func (r *anObject) A() string { -// release := r.cs.WithValue("key", "val") -// defer release() -// r.B() -// ... -// } +// func (r *anObject) A() string { +// release := r.cs.WithValue("key", "val") +// defer release() +// r.B() +// ... +// } // -// func (r *anObject) B() string { -// ... -// r.C() -// ... -// } +// func (r *anObject) B() string { +// ... +// r.C() +// ... +// } // -// func (r *anObject) C() string { -// val := r.Ctx().Value("key") -// ... -// } +// func (r *anObject) C() string { +// val := r.Ctx().Value("key") +// ... +// } type ContextStack interface { // Ctx retrieves the current context for the current goroutine. Ctx() context.Context From 9c430919f2fd5d7114d3f24d4009b5aacc51ea4b Mon Sep 17 00:00:00 2001 From: jslching <38669839+jslching@users.noreply.github.com> Date: Mon, 6 Nov 2023 10:47:03 -0500 Subject: [PATCH 2/2] add max_depth --- util/ctxutil/stack.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/util/ctxutil/stack.go b/util/ctxutil/stack.go index 0911569..71458b5 100644 --- a/util/ctxutil/stack.go +++ b/util/ctxutil/stack.go @@ -21,11 +21,16 @@ func NewStack() ContextStack { c.mutex.Lock() size := len(c.stacks) depths := map[int64]int{} + maxDepth := 0 for gid, entry := range c.stacks { - depths[gid] = stackDepth(entry.stack) + depth := stackDepth(entry.stack) + depths[gid] = depth + if depth > maxDepth { + maxDepth = depth + } } c.mutex.Unlock() - log.Warn("ContextStack", "size", size, "depths", depths) + log.Warn("ContextStack", "size", size, "max_depth", maxDepth, "depths", depths) } }() return c