github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/chain/swarm/tracing/tracing.go (about)

     1  package tracing
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"os"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/ethereum/go-ethereum/log"
    12  	"github.com/ethereum/go-ethereum/swarm/spancontext"
    13  
    14  	opentracing "github.com/opentracing/opentracing-go"
    15  	jaeger "github.com/uber/jaeger-client-go"
    16  	jaegercfg "github.com/uber/jaeger-client-go/config"
    17  	cli "gopkg.in/urfave/cli.v1"
    18  )
    19  
    20  var (
    21  	// Enabled turns tracing on for the current swarm instance
    22  	Enabled bool = false
    23  	store        = spanStore{}
    24  )
    25  
    26  const (
    27  	// TracingEnabledFlag is the CLI flag name to use to enable trace collections.
    28  	TracingEnabledFlag = "tracing"
    29  
    30  	// StoreLabelId is the context value key of the name of the span to be saved
    31  	StoreLabelId = "span_save_id"
    32  
    33  	// StoreLabelMeta is the context value key that together with StoreLabelId constitutes the retrieval key for saved spans in the span store
    34  	// StartSaveSpan and ShiftSpanByKey
    35  	StoreLabelMeta = "span_save_meta"
    36  )
    37  
    38  var (
    39  	Closer io.Closer
    40  )
    41  
    42  var (
    43  	TracingFlag = cli.BoolFlag{
    44  		Name:  TracingEnabledFlag,
    45  		Usage: "Enable tracing",
    46  	}
    47  	TracingEndpointFlag = cli.StringFlag{
    48  		Name:  "tracing.endpoint",
    49  		Usage: "Tracing endpoint",
    50  		Value: "0.0.0.0:6831",
    51  	}
    52  	TracingSvcFlag = cli.StringFlag{
    53  		Name:  "tracing.svc",
    54  		Usage: "Tracing service name",
    55  		Value: "swarm",
    56  	}
    57  )
    58  
    59  // Flags holds all command-line flags required for tracing collection.
    60  var Flags = []cli.Flag{
    61  	TracingFlag,
    62  	TracingEndpointFlag,
    63  	TracingSvcFlag,
    64  }
    65  
    66  // Init enables or disables the open tracing system.
    67  func init() {
    68  	for _, arg := range os.Args {
    69  		if flag := strings.TrimLeft(arg, "-"); flag == TracingEnabledFlag {
    70  			Enabled = true
    71  		}
    72  	}
    73  }
    74  
    75  func Setup(ctx *cli.Context) {
    76  	if Enabled {
    77  		log.Info("Enabling opentracing")
    78  		var (
    79  			endpoint = ctx.GlobalString(TracingEndpointFlag.Name)
    80  			svc      = ctx.GlobalString(TracingSvcFlag.Name)
    81  		)
    82  
    83  		Closer = initTracer(endpoint, svc)
    84  	}
    85  }
    86  
    87  func initTracer(endpoint, svc string) (closer io.Closer) {
    88  	// Sample configuration for testing. Use constant sampling to sample every trace
    89  	// and enable LogSpan to log every span via configured Logger.
    90  	cfg := jaegercfg.Configuration{
    91  		Sampler: &jaegercfg.SamplerConfig{
    92  			Type:  jaeger.SamplerTypeConst,
    93  			Param: 1,
    94  		},
    95  		Reporter: &jaegercfg.ReporterConfig{
    96  			LogSpans:            true,
    97  			BufferFlushInterval: 1 * time.Second,
    98  			LocalAgentHostPort:  endpoint,
    99  		},
   100  	}
   101  
   102  	// Example logger and metrics factory. Use github.com/uber/jaeger-client-go/log
   103  	// and github.com/uber/jaeger-lib/metrics respectively to bind to real logging and metrics
   104  	// frameworks.
   105  	//jLogger := jaegerlog.StdLogger
   106  	//jMetricsFactory := metrics.NullFactory
   107  
   108  	// Initialize tracer with a logger and a metrics factory
   109  	closer, err := cfg.InitGlobalTracer(
   110  		svc,
   111  		//jaegercfg.Logger(jLogger),
   112  		//jaegercfg.Metrics(jMetricsFactory),
   113  		//jaegercfg.Observer(rpcmetrics.NewObserver(jMetricsFactory, rpcmetrics.DefaultNameNormalizer)),
   114  	)
   115  	if err != nil {
   116  		log.Error("Could not initialize Jaeger tracer", "err", err)
   117  	}
   118  
   119  	return closer
   120  }
   121  
   122  // spanStore holds saved spans
   123  type spanStore struct {
   124  	spans sync.Map
   125  }
   126  
   127  // StartSaveSpan stores the span specified in the passed context for later retrieval
   128  // The span object but be context value on the key StoreLabelId.
   129  // It will be stored under the the following string key context.Value(StoreLabelId)|.|context.Value(StoreLabelMeta)
   130  func StartSaveSpan(ctx context.Context) context.Context {
   131  	if !Enabled {
   132  		return ctx
   133  	}
   134  	traceId := ctx.Value(StoreLabelId)
   135  
   136  	if traceId != nil {
   137  		traceStr := traceId.(string)
   138  		var sp opentracing.Span
   139  		ctx, sp = spancontext.StartSpan(
   140  			ctx,
   141  			traceStr,
   142  		)
   143  		traceMeta := ctx.Value(StoreLabelMeta)
   144  		if traceMeta != nil {
   145  			traceStr = traceStr + "." + traceMeta.(string)
   146  		}
   147  		store.spans.Store(traceStr, sp)
   148  	}
   149  	return ctx
   150  }
   151  
   152  // ShiftSpanByKey retrieves the span stored under the key of the string given as argument
   153  // The span is then deleted from the store
   154  func ShiftSpanByKey(k string) opentracing.Span {
   155  	if !Enabled {
   156  		return nil
   157  	}
   158  	span, spanOk := store.spans.Load(k)
   159  	if !spanOk {
   160  		return nil
   161  	}
   162  	store.spans.Delete(k)
   163  	return span.(opentracing.Span)
   164  }
   165  
   166  // FinishSpans calls `Finish()` on all stored spans
   167  // It should be called on instance shutdown
   168  func FinishSpans() {
   169  	store.spans.Range(func(_, v interface{}) bool {
   170  		v.(opentracing.Span).Finish()
   171  		return true
   172  	})
   173  }