gorgonia.org/gorgonia@v0.9.17/x/vm/tracer.go (about) 1 package xvm 2 3 import ( 4 "context" 5 "reflect" 6 "runtime" 7 "time" 8 ) 9 10 // Trace the nodes states 11 type Trace struct { 12 //fmt.Println(runtime.FuncForPC(reflect.ValueOf(state).Pointer()).Name()) 13 StateFunction string 14 ID int64 15 Start time.Time 16 End time.Time `json:",omitempty"` 17 } 18 19 type chanTracerContextKey int 20 21 const ( 22 globalTracerContextKey chanTracerContextKey = 0 23 ) 24 25 // WithTracing initializes a tracing channel and adds it to the context 26 func WithTracing(parent context.Context) (context.Context, <-chan Trace) { 27 c := make(chan Trace, 0) 28 return context.WithValue(parent, globalTracerContextKey, c), c 29 } 30 31 // CloseTracing the tracing channel to avoid context leak. 32 // it is a nil op if context does not carry tracing information 33 func CloseTracing(ctx context.Context) { 34 c := extractTracingChannel(ctx) 35 if c != nil { 36 close(c) 37 } 38 } 39 40 func extractTracingChannel(ctx context.Context) chan<- Trace { 41 if ctx == nil { 42 return nil 43 } 44 if c := ctx.Value(globalTracerContextKey); c != nil { 45 return c.(chan Trace) 46 } 47 return nil 48 } 49 50 var now = time.Now 51 52 func trace(ctx context.Context, t *Trace, n *node, state stateFn) *Trace { 53 traceC := extractTracingChannel(ctx) 54 if traceC == nil { 55 return t 56 } 57 if t == nil { 58 t = &Trace{ 59 ID: n.id, 60 StateFunction: runtime.FuncForPC(reflect.ValueOf(state).Pointer()).Name(), 61 Start: now(), 62 } 63 } else { 64 t.End = now() 65 } 66 select { 67 case traceC <- *t: 68 case <-ctx.Done(): 69 } 70 return t 71 }