go-ethereum/swarm/tracing/tracing.go

174 lines
4.2 KiB
Go

package tracing
import (
"context"
"io"
"os"
"strings"
"sync"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/spancontext"
opentracing "github.com/opentracing/opentracing-go"
jaeger "github.com/uber/jaeger-client-go"
jaegercfg "github.com/uber/jaeger-client-go/config"
cli "gopkg.in/urfave/cli.v1"
)
var (
// Enabled turns tracing on for the current swarm instance
Enabled bool = false
store = spanStore{}
)
const (
// TracingEnabledFlag is the CLI flag name to use to enable trace collections.
TracingEnabledFlag = "tracing"
// StoreLabelId is the context value key of the name of the span to be saved
StoreLabelId = "span_save_id"
// StoreLabelMeta is the context value key that together with StoreLabelId constitutes the retrieval key for saved spans in the span store
// StartSaveSpan and ShiftSpanByKey
StoreLabelMeta = "span_save_meta"
)
var (
Closer io.Closer
)
var (
TracingFlag = cli.BoolFlag{
Name: TracingEnabledFlag,
Usage: "Enable tracing",
}
TracingEndpointFlag = cli.StringFlag{
Name: "tracing.endpoint",
Usage: "Tracing endpoint",
Value: "0.0.0.0:6831",
}
TracingSvcFlag = cli.StringFlag{
Name: "tracing.svc",
Usage: "Tracing service name",
Value: "swarm",
}
)
// Flags holds all command-line flags required for tracing collection.
var Flags = []cli.Flag{
TracingFlag,
TracingEndpointFlag,
TracingSvcFlag,
}
// Init enables or disables the open tracing system.
func init() {
for _, arg := range os.Args {
if flag := strings.TrimLeft(arg, "-"); flag == TracingEnabledFlag {
Enabled = true
}
}
}
func Setup(ctx *cli.Context) {
if Enabled {
log.Info("Enabling opentracing")
var (
endpoint = ctx.GlobalString(TracingEndpointFlag.Name)
svc = ctx.GlobalString(TracingSvcFlag.Name)
)
Closer = initTracer(endpoint, svc)
}
}
func initTracer(endpoint, svc string) (closer io.Closer) {
// Sample configuration for testing. Use constant sampling to sample every trace
// and enable LogSpan to log every span via configured Logger.
cfg := jaegercfg.Configuration{
Sampler: &jaegercfg.SamplerConfig{
Type: jaeger.SamplerTypeConst,
Param: 1,
},
Reporter: &jaegercfg.ReporterConfig{
LogSpans: true,
BufferFlushInterval: 1 * time.Second,
LocalAgentHostPort: endpoint,
},
}
// Example logger and metrics factory. Use github.com/uber/jaeger-client-go/log
// and github.com/uber/jaeger-lib/metrics respectively to bind to real logging and metrics
// frameworks.
//jLogger := jaegerlog.StdLogger
//jMetricsFactory := metrics.NullFactory
// Initialize tracer with a logger and a metrics factory
closer, err := cfg.InitGlobalTracer(
svc,
//jaegercfg.Logger(jLogger),
//jaegercfg.Metrics(jMetricsFactory),
//jaegercfg.Observer(rpcmetrics.NewObserver(jMetricsFactory, rpcmetrics.DefaultNameNormalizer)),
)
if err != nil {
log.Error("Could not initialize Jaeger tracer", "err", err)
}
return closer
}
// spanStore holds saved spans
type spanStore struct {
spans sync.Map
}
// StartSaveSpan stores the span specified in the passed context for later retrieval
// The span object but be context value on the key StoreLabelId.
// It will be stored under the the following string key context.Value(StoreLabelId)|.|context.Value(StoreLabelMeta)
func StartSaveSpan(ctx context.Context) context.Context {
if !Enabled {
return ctx
}
traceId := ctx.Value(StoreLabelId)
if traceId != nil {
traceStr := traceId.(string)
var sp opentracing.Span
ctx, sp = spancontext.StartSpan(
ctx,
traceStr,
)
traceMeta := ctx.Value(StoreLabelMeta)
if traceMeta != nil {
traceStr = traceStr + "." + traceMeta.(string)
}
store.spans.Store(traceStr, sp)
}
return ctx
}
// ShiftSpanByKey retrieves the span stored under the key of the string given as argument
// The span is then deleted from the store
func ShiftSpanByKey(k string) opentracing.Span {
if !Enabled {
return nil
}
span, spanOk := store.spans.Load(k)
if !spanOk {
return nil
}
store.spans.Delete(k)
return span.(opentracing.Span)
}
// FinishSpans calls `Finish()` on all stored spans
// It should be called on instance shutdown
func FinishSpans() {
store.spans.Range(func(_, v interface{}) bool {
v.(opentracing.Span).Finish()
return true
})
}