Ejemplo n.º 1
0
// TestTeeTracerSpanRefs verifies that ChildOf/FollowsFrom relations are
// reflected correctly in the underlying spans.
func TestTeeTracerSpanRefs(t *testing.T) {
	r1 := basictracer.NewInMemoryRecorder()
	t1 := basictracer.NewWithOptions(basictracer.Options{
		Recorder:     r1,
		ShouldSample: func(traceID uint64) bool { return true }, // always sample
	})
	r2 := basictracer.NewInMemoryRecorder()
	t2 := basictracer.NewWithOptions(basictracer.Options{
		Recorder:     r2,
		ShouldSample: func(traceID uint64) bool { return true }, // always sample
	})
	tr := NewTeeTracer(t1, t2)

	root := tr.StartSpan("x")
	child := tr.StartSpan("x", opentracing.ChildOf(root.Context()))
	child.Finish()
	root.Finish()

	for _, spans := range [][]basictracer.RawSpan{r1.GetSpans(), r2.GetSpans()} {
		if e, a := 2, len(spans); a != e {
			t.Fatalf("expected %d, got %d", e, a)
		}

		if e, a := spans[0].Context.TraceID, spans[1].Context.TraceID; a != e {
			t.Errorf("expected %d, got %d", e, a)
		}
		if e, a := spans[1].Context.SpanID, spans[0].ParentSpanID; a != e {
			t.Errorf("expected %d, got %d", e, a)
		}
	}
}
Ejemplo n.º 2
0
// testingTracer creates a Tracer that appends the events to the given slice.
func testingTracer(ev *events) opentracing.Tracer {
	opts := basictracer.DefaultOptions()
	opts.ShouldSample = func(_ uint64) bool { return true }
	opts.NewSpanEventListener = func() func(basictracer.SpanEvent) {
		// The op variable is used in the returned function and is associated with
		// a span; it lives for as long as the span is open.
		var op string
		return func(e basictracer.SpanEvent) {
			switch t := e.(type) {
			case basictracer.EventCreate:
				op = t.OperationName
				*ev = append(*ev, fmt.Sprintf("%s:start", op))
			case basictracer.EventFinish:
				*ev = append(*ev, fmt.Sprintf("%s:finish", op))
			case basictracer.EventLogFields:
				*ev = append(*ev, fmt.Sprintf("%s:%s", op, t.Fields[0].Value()))
			case basictracer.EventLog:
				panic("EventLog is deprecated")
			}
		}
	}
	opts.DebugAssertUseAfterFinish = true
	// We don't care about the recorder but we need to set it to something.
	opts.Recorder = &basictracer.InMemorySpanRecorder{}
	return basictracer.NewWithOptions(opts)
}
Ejemplo n.º 3
0
// JoinOrNewSnowball returns a Span which records directly via the specified
// callback. If the given DelegatingCarrier is nil, a new Span is created.
// otherwise, the created Span is a child.
func JoinOrNewSnowball(opName string, carrier *Span, callback func(sp basictracer.RawSpan)) (opentracing.Span, error) {
	tr := basictracer.NewWithOptions(defaultOptions(callback))
	sp, err := JoinOrNew(tr, carrier, opName)
	if err == nil {
		// We definitely want to sample a Snowball trace.
		// This must be set *before* SetBaggageItem, as that will otherwise be ignored.
		ext.SamplingPriority.Set(sp, 1)
		sp.SetBaggageItem(Snowball, "1")
	}
	return sp, err
}
Ejemplo n.º 4
0
// NewTracerAndSpanFor7881 creates a new tracer and a root span. The tracer is
// to be used for tracking down #7881; it runs a callback for each finished span
// (and the callback used accumulates the spans in a SQL txn).
func NewTracerAndSpanFor7881(
	callback func(sp basictracer.RawSpan),
) (opentracing.Span, opentracing.Tracer, error) {
	opts := basictracerOptions(callback)
	// Don't trim the logs in "unsampled" spans". Note that this tracer does not
	// use sampling; instead it uses an ad-hoc mechanism for marking spans of
	// interest.
	opts.TrimUnsampledSpans = false
	tr := basictracer.NewWithOptions(opts)
	sp, err := JoinOrNew(tr, nil, "sql txn")
	return sp, tr, err
}
Ejemplo n.º 5
0
	return sp, err
}

func defaultOptions(recorder func(basictracer.RawSpan)) basictracer.Options {
	opts := basictracer.DefaultOptions()
	opts.ShouldSample = func(traceID int64) bool { return false }
	opts.TrimUnsampledSpans = true
	opts.Recorder = CallbackRecorder(recorder)
	opts.NewSpanEventListener = basictracer.NetTraceIntegrator
	opts.DebugAssertUseAfterFinish = true // provoke crash on use-after-Finish
	return opts
}

// newTracer implements NewTracer and allows that function to be mocked out via Disable().
var newTracer = func() opentracing.Tracer {
	return basictracer.NewWithOptions(defaultOptions(func(_ basictracer.RawSpan) {}))
}

// NewTracer creates a Tracer which records to the net/trace
// endpoint.
func NewTracer() opentracing.Tracer {
	return newTracer()
}

// EnsureContext checks whether the given context.Context contains a Span. If
// not, it creates one using the provided Tracer and wraps it in the returned
// Span. The returned closure must be called after the request has been fully
// processed.
func EnsureContext(ctx context.Context, tracer opentracing.Tracer) (context.Context, func()) {
	_, _, funcName := caller.Lookup(1)
	if opentracing.SpanFromContext(ctx) == nil {
Ejemplo n.º 6
0
// By default, if a lightstep token is specified we trace to both Lightstep and
// net/trace. If this flag is enabled, we will only trace to Lightstep.
var lightstepOnly = envutil.EnvOrDefaultBool("COCKROACH_LIGHTSTEP_ONLY", false)

// newTracer implements NewTracer and allows that function to be mocked out via Disable().
var newTracer = func() opentracing.Tracer {
	if lightstepToken != "" {
		lsTr := lightstep.NewTracer(lightstep.Options{
			AccessToken:    lightstepToken,
			MaxLogsPerSpan: maxLogsPerSpan,
			UseGRPC:        true,
		})
		if lightstepOnly {
			return lsTr
		}
		basicTr := basictracer.NewWithOptions(basictracerOptions(nil))
		// The TeeTracer uses the first tracer for serialization of span contexts;
		// lightspan needs to be first because it correlates spans between nodes.
		return NewTeeTracer(lsTr, basicTr)
	}
	return basictracer.NewWithOptions(basictracerOptions(nil))
}

// NewTracer creates a Tracer which records to the net/trace
// endpoint.
func NewTracer() opentracing.Tracer {
	return newTracer()
}

// EnsureContext checks whether the given context.Context contains a Span. If
// not, it creates one using the provided Tracer and wraps it in the returned
Ejemplo n.º 7
0
	if err == nil {
		sp.SetBaggageItem(Snowball, "1")
		// We definitely want to sample a Snowball trace.
		ext.SamplingPriority.Set(sp, 1)
	}
	return sp, err
}

// newTracer implements NewTracer and allows that function to be mocked out via Disable().
var newTracer = func() opentracing.Tracer {
	opts := basictracer.DefaultOptions()
	opts.TrimUnsampledSpans = true
	opts.Recorder = CallbackRecorder(func(_ basictracer.RawSpan) {})
	opts.NewSpanEventListener = basictracer.NetTraceIntegrator
	opts.DebugAssertUseAfterFinish = true // provoke crash on use-after-Finish
	return basictracer.NewWithOptions(opts)
}

// NewTracer creates a Tracer which records to the net/trace
// endpoint.
func NewTracer() opentracing.Tracer {
	return newTracer()
}

// SpanFromContext returns the Span obtained from the context or, if none is
// found, a new one started through the tracer. Callers should call (or defer)
// the returned cleanup func as well to ensure that the span is Finish()ed, but
// callers should *not* attempt to call Finish directly -- in the case where the
// span was obtained from the context, it is not the caller's to Finish.
func SpanFromContext(opName string, tracer opentracing.Tracer, ctx context.Context) (opentracing.Span, func()) {
	sp := opentracing.SpanFromContext(ctx)
Ejemplo n.º 8
0
func TestTeeTracer(t *testing.T) {
	r1 := basictracer.NewInMemoryRecorder()
	t1 := basictracer.NewWithOptions(basictracer.Options{
		Recorder:     r1,
		ShouldSample: func(traceID uint64) bool { return true }, // always sample
	})
	r2 := basictracer.NewInMemoryRecorder()
	t2 := basictracer.NewWithOptions(basictracer.Options{
		Recorder:     r2,
		ShouldSample: func(traceID uint64) bool { return true }, // always sample
	})
	tr := NewTeeTracer(t1, t2)

	span := tr.StartSpan("x")
	span.LogKV("k1", "v1", "k2", "v2")
	span.SetTag("tag", "value")
	span.SetBaggageItem("baggage", "baggage-value")
	if e, a := "baggage-value", span.BaggageItem("baggage"); a != e {
		t.Errorf("expected %s, got %s", e, a)
	}

	spanCtx := span.Context()
	var ctxBuffer bytes.Buffer
	if err := tr.Inject(spanCtx, opentracing.Binary, &ctxBuffer); err != nil {
		t.Fatal(err)
	}

	decodedCtx, err := tr.Extract(opentracing.Binary, &ctxBuffer)
	if err != nil {
		t.Fatal(err)
	}
	span2 := tr.StartSpan("y", opentracing.FollowsFrom(decodedCtx))
	span2.LogEvent("event2")
	if e, a := "baggage-value", span2.BaggageItem("baggage"); a != e {
		t.Errorf("expected %s, got %s", e, a)
	}
	span.Finish()
	span2.Finish()

	for _, spans := range [][]basictracer.RawSpan{r1.GetSpans(), r2.GetSpans()} {
		if e, a := 2, len(spans); a != e {
			t.Fatalf("expected %d, got %d", e, a)
		}

		if e, a := "x", spans[0].Operation; a != e {
			t.Errorf("expected %s, got %s", e, a)
		}
		if e, a := (opentracing.Tags{"tag": "value"}), spans[0].Tags; !reflect.DeepEqual(a, e) {
			t.Errorf("expected %s, got %s", e, a)
		}
		if e, a := "k1:v1", spans[0].Logs[0].Fields[0].String(); a != e {
			t.Errorf("expected %s, got %s", e, a)
		}
		if e, a := "k2:v2", spans[0].Logs[0].Fields[1].String(); a != e {
			t.Errorf("expected %s, got %s", e, a)
		}
		if e, a := 1, len(spans[0].Context.Baggage); a != e {
			t.Errorf("expected %d, got %d", e, a)
		}

		if e, a := "y", spans[1].Operation; a != e {
			t.Errorf("expected %s, got %s", e, a)
		}
		if e, a := opentracing.Tags(nil), spans[1].Tags; !reflect.DeepEqual(a, e) {
			t.Errorf("expected %s, got %s", e, a)
		}
		if e, a := "event:event2", spans[1].Logs[0].Fields[0].String(); a != e {
			t.Errorf("expected %s, got %s", e, a)
		}
		if e, a := 1, len(spans[1].Context.Baggage); a != e {
			t.Errorf("expected %d, got %d", e, a)
		}
	}
}
Ejemplo n.º 9
0
// NewTracerWithOptions creates a new opentracing.Tracer that records spans to
// the given appdash.Collector.
func NewTracerWithOptions(c appdash.Collector, options Options) opentracing.Tracer {
	opts := basictracer.DefaultOptions()
	opts.ShouldSample = options.ShouldSample
	opts.Recorder = NewRecorder(c, options)
	return basictracer.NewWithOptions(opts)
}