mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-22 08:23:50 +01:00
package trace: track activeChildTasks in a set if debugEnabled=true
refs #358
This commit is contained in:
parent
d5ce578929
commit
e500d9ee26
@ -93,9 +93,11 @@ package trace
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
runtimedebug "runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kr/pretty"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/zrepl/zrepl/util/chainlock"
|
"github.com/zrepl/zrepl/util/chainlock"
|
||||||
@ -120,13 +122,17 @@ func RegisterMetrics(r prometheus.Registerer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type traceNode struct {
|
type traceNode struct {
|
||||||
|
// NOTE: members with prefix debug are only valid if the package variable debugEnabled is true.
|
||||||
|
|
||||||
id string
|
id string
|
||||||
annotation string
|
annotation string
|
||||||
parentTask *traceNode
|
parentTask *traceNode
|
||||||
|
debugCreationStack string // debug: stack trace of when the traceNode was created
|
||||||
|
|
||||||
mtx chainlock.L
|
mtx chainlock.L
|
||||||
|
|
||||||
activeChildTasks int32 // only for task nodes, insignificant for span nodes
|
activeChildTasks int32 // only for task nodes, insignificant for span nodes
|
||||||
|
debugActiveChildTasks map[*traceNode]bool // debug: set of active child tasks
|
||||||
parentSpan *traceNode
|
parentSpan *traceNode
|
||||||
activeChildSpan *traceNode // nil if task or span doesn't have an active child span
|
activeChildSpan *traceNode // nil if task or span doesn't have an active child span
|
||||||
|
|
||||||
@ -137,6 +143,14 @@ type traceNode struct {
|
|||||||
func (s *traceNode) StartedAt() time.Time { return s.startedAt }
|
func (s *traceNode) StartedAt() time.Time { return s.startedAt }
|
||||||
func (s *traceNode) EndedAt() time.Time { return s.endedAt }
|
func (s *traceNode) EndedAt() time.Time { return s.endedAt }
|
||||||
|
|
||||||
|
// caller must hold mtx
|
||||||
|
func (s *traceNode) debugString() string {
|
||||||
|
if !debugEnabled {
|
||||||
|
return "<debugEnabled=false>"
|
||||||
|
}
|
||||||
|
return pretty.Sprint(s)
|
||||||
|
}
|
||||||
|
|
||||||
// Returned from WithTask or WithSpan.
|
// Returned from WithTask or WithSpan.
|
||||||
// Must be called once the task or span ends.
|
// Must be called once the task or span ends.
|
||||||
// See package-level docs for nesting rules.
|
// See package-level docs for nesting rules.
|
||||||
@ -196,8 +210,16 @@ func WithTask(ctx context.Context, taskName string) (context.Context, DoneFunc)
|
|||||||
endedAt: time.Time{},
|
endedAt: time.Time{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if debugEnabled {
|
||||||
|
this.debugCreationStack = string(runtimedebug.Stack())
|
||||||
|
this.debugActiveChildTasks = map[*traceNode]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
if parentTask != nil {
|
if parentTask != nil {
|
||||||
this.parentTask.activeChildTasks++
|
this.parentTask.activeChildTasks++
|
||||||
|
if debugEnabled {
|
||||||
|
this.parentTask.debugActiveChildTasks[this] = true
|
||||||
|
}
|
||||||
parentTask.mtx.Unlock()
|
parentTask.mtx.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +240,7 @@ func WithTask(ctx context.Context, taskName string) (context.Context, DoneFunc)
|
|||||||
defer this.mtx.Lock().Unlock()
|
defer this.mtx.Lock().Unlock()
|
||||||
|
|
||||||
if this.activeChildTasks != 0 {
|
if this.activeChildTasks != 0 {
|
||||||
panic(errors.Wrapf(ErrTaskStillHasActiveChildTasks, "end task: %v active child tasks", this.activeChildTasks))
|
panic(errors.WithMessagef(ErrTaskStillHasActiveChildTasks, "end task: %v active child tasks\n: %s", this.activeChildTasks, this.debugString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// support idempotent task ends
|
// support idempotent task ends
|
||||||
@ -229,8 +251,11 @@ func WithTask(ctx context.Context, taskName string) (context.Context, DoneFunc)
|
|||||||
|
|
||||||
if this.parentTask != nil {
|
if this.parentTask != nil {
|
||||||
this.parentTask.activeChildTasks--
|
this.parentTask.activeChildTasks--
|
||||||
|
if debugEnabled {
|
||||||
|
delete(this.parentTask.debugActiveChildTasks, this)
|
||||||
|
}
|
||||||
if this.parentTask.activeChildTasks < 0 {
|
if this.parentTask.activeChildTasks < 0 {
|
||||||
panic("impl error: parent task with negative activeChildTasks count")
|
panic(fmt.Sprintf("impl error: parent task with negative activeChildTasks count: %s", this.debugString()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -279,6 +304,10 @@ func WithSpan(ctx context.Context, annotation string) (context.Context, DoneFunc
|
|||||||
endedAt: time.Time{},
|
endedAt: time.Time{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if debugEnabled {
|
||||||
|
this.debugCreationStack = string(runtimedebug.Stack())
|
||||||
|
}
|
||||||
|
|
||||||
parentSpan.mtx.HoldWhile(func() {
|
parentSpan.mtx.HoldWhile(func() {
|
||||||
if parentSpan.activeChildSpan != nil {
|
if parentSpan.activeChildSpan != nil {
|
||||||
panic(ErrAlreadyActiveChildSpan)
|
panic(ErrAlreadyActiveChildSpan)
|
||||||
|
Loading…
Reference in New Issue
Block a user