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  }