github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/trace/tracing.go (about) 1 // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0. 2 3 package trace 4 5 import ( 6 "context" 7 "fmt" 8 "os" 9 "path/filepath" 10 "sort" 11 "text/tabwriter" 12 "time" 13 14 "github.com/cheynewallace/tabby" 15 "github.com/opentracing/opentracing-go" 16 "github.com/pingcap/log" 17 "go.uber.org/zap" 18 "sourcegraph.com/sourcegraph/appdash" 19 traceImpl "sourcegraph.com/sourcegraph/appdash/opentracing" 20 ) 21 22 var getTraceFileName = timestampTraceFileName 23 24 func timestampTraceFileName() string { 25 return filepath.Join(os.TempDir(), time.Now().Format("br.trace.2006-01-02T15.04.05Z0700")) 26 } 27 28 // TracerStartSpan starts the tracer for BR 29 func TracerStartSpan(ctx context.Context) (context.Context, *appdash.MemoryStore) { 30 store := appdash.NewMemoryStore() 31 tracer := traceImpl.NewTracer(store) 32 span := tracer.StartSpan("trace") 33 ctx = opentracing.ContextWithSpan(ctx, span) 34 return ctx, store 35 } 36 37 // TracerFinishSpan finishes the tracer for BR 38 func TracerFinishSpan(ctx context.Context, store appdash.Queryer) { 39 span := opentracing.SpanFromContext(ctx) 40 traces, err := store.Traces(appdash.TracesOpts{}) 41 if err != nil { 42 log.Error("fail to get traces", zap.Error(err)) 43 return 44 } 45 span.Finish() 46 if len(traces) < 1 { 47 return 48 } 49 trace := traces[0] 50 51 filename := getTraceFileName() 52 file, err := os.Create(filename) 53 if err != nil { 54 log.Error("fail to open trace file", zap.Error(err)) 55 return 56 } 57 defer file.Close() 58 fmt.Fprintf(os.Stderr, "Detail BR trace in %s \n", filename) 59 log.Info("Detail BR trace", zap.String("filename", filename)) 60 tub := tabby.NewCustom(tabwriter.NewWriter(file, 0, 0, 2, ' ', 0)) 61 62 dfsTree(trace, "", false, tub) 63 tub.Print() 64 } 65 66 func dfsTree(t *appdash.Trace, prefix string, isLast bool, tub *tabby.Tabby) { 67 var newPrefix, suffix string 68 if len(prefix) == 0 { 69 newPrefix = prefix + " " 70 } else { 71 if !isLast { 72 suffix = "├─" 73 newPrefix = prefix + "│ " 74 } else { 75 suffix = "└─" 76 newPrefix = prefix + " " 77 } 78 } 79 80 var start time.Time 81 var duration time.Duration 82 if e, err := t.TimespanEvent(); err == nil { 83 start = e.Start() 84 end := e.End() 85 duration = end.Sub(start) 86 } 87 88 tub.AddLine(prefix+suffix+t.Span.Name(), start.Format("15:04:05.000000"), duration.String()) 89 90 // Sort events by their start time 91 sort.Slice(t.Sub, func(i, j int) bool { 92 var istart, jstart time.Time 93 if ievent, err := t.Sub[i].TimespanEvent(); err == nil { 94 istart = ievent.Start() 95 } 96 if jevent, err := t.Sub[j].TimespanEvent(); err == nil { 97 jstart = jevent.Start() 98 } 99 return istart.Before(jstart) 100 }) 101 102 for i, sp := range t.Sub { 103 dfsTree(sp, newPrefix, i == (len(t.Sub))-1 /*last element of array*/, tub) 104 } 105 }