Dep helper (#2151)

* Add dep task to update go dependencies

* Update go dependencies
This commit is contained in:
Manuel Alejandro de Brito Fontes 2018-09-29 19:47:07 -03:00 committed by Miek Gieben
parent 8f8b81f56b
commit 0e8977761d
764 changed files with 172 additions and 267451 deletions

View file

@ -1,58 +0,0 @@
package opentracing
import (
"testing"
ot "github.com/opentracing/opentracing-go"
"github.com/stretchr/testify/assert"
)
func TestConfigurationDefaults(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
assert.Equal(true, config.Enabled)
assert.Equal(false, config.Debug)
assert.Equal(float64(1), config.SampleRate)
assert.Equal("opentracing.test", config.ServiceName)
assert.Equal("localhost", config.AgentHostname)
assert.Equal("8126", config.AgentPort)
}
func TestConfiguration(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
config.SampleRate = 0
config.ServiceName = "api-intake"
config.AgentHostname = "ddagent.consul.local"
config.AgentPort = "58126"
tracer, closer, err := NewTracer(config)
assert.NotNil(tracer)
assert.NotNil(closer)
assert.Nil(err)
assert.Equal("api-intake", tracer.(*Tracer).config.ServiceName)
}
func TestTracerServiceName(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
config.ServiceName = ""
tracer, closer, err := NewTracer(config)
assert.Nil(tracer)
assert.Nil(closer)
assert.NotNil(err)
assert.Equal("A Datadog Tracer requires a valid `ServiceName` set", err.Error())
}
func TestDisabledTracer(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
config.Enabled = false
tracer, closer, err := NewTracer(config)
assert.IsType(&ot.NoopTracer{}, tracer)
assert.IsType(&noopCloser{}, closer)
assert.Nil(err)
}

View file

@ -1,29 +0,0 @@
package opentracing
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSpanContextBaggage(t *testing.T) {
assert := assert.New(t)
ctx := SpanContext{}
ctx = ctx.WithBaggageItem("key", "value")
assert.Equal("value", ctx.baggage["key"])
}
func TestSpanContextIterator(t *testing.T) {
assert := assert.New(t)
baggageIterator := make(map[string]string)
ctx := SpanContext{baggage: map[string]string{"key": "value"}}
ctx.ForeachBaggageItem(func(k, v string) bool {
baggageIterator[k] = v
return true
})
assert.Len(baggageIterator, 1)
assert.Equal("value", baggageIterator["key"])
}

View file

@ -1,30 +0,0 @@
package opentracing_test
import (
"context"
opentracing "github.com/opentracing/opentracing-go"
)
// You can leverage the Golang `Context` for intra-process propagation of
// Spans. In this example we create a root Span, so that it can be reused
// in a nested function to create a child Span.
func Example_startContext() {
// create a new root Span and return a new Context that includes
// the Span itself
ctx := context.Background()
rootSpan, ctx := opentracing.StartSpanFromContext(ctx, "web.request")
defer rootSpan.Finish()
requestHandler(ctx)
}
func requestHandler(ctx context.Context) {
// retrieve the previously set root Span
span := opentracing.SpanFromContext(ctx)
span.SetTag("resource.name", "/")
// or simply create a new child Span from the previous Context
childSpan, _ := opentracing.StartSpanFromContext(ctx, "sql.query")
defer childSpan.Finish()
}

View file

@ -1,30 +0,0 @@
package opentracing_test
import (
// ddtrace namespace is suggested
ddtrace "github.com/DataDog/dd-trace-go/opentracing"
opentracing "github.com/opentracing/opentracing-go"
)
func Example_initialization() {
// create a Tracer configuration
config := ddtrace.NewConfiguration()
config.ServiceName = "api-intake"
config.AgentHostname = "ddagent.consul.local"
// initialize a Tracer and ensure a graceful shutdown
// using the `closer.Close()`
tracer, closer, err := ddtrace.NewTracer(config)
if err != nil {
// handle the configuration error
}
defer closer.Close()
// set the Datadog tracer as a GlobalTracer
opentracing.SetGlobalTracer(tracer)
startWebServer()
}
func startWebServer() {
// start a web server
}

View file

@ -1,24 +0,0 @@
package opentracing_test
import (
opentracing "github.com/opentracing/opentracing-go"
)
// You can use the GlobalTracer to create a root Span. If you need to create a hierarchy,
// simply use the `ChildOf` reference
func Example_startSpan() {
// use the GlobalTracer previously set
rootSpan := opentracing.StartSpan("web.request")
defer rootSpan.Finish()
// set the reference to create a hierarchy of spans
reference := opentracing.ChildOf(rootSpan.Context())
childSpan := opentracing.StartSpan("sql.query", reference)
defer childSpan.Finish()
dbQuery()
}
func dbQuery() {
// start a database query
}

View file

@ -1,81 +0,0 @@
package opentracing
import (
"net/http"
"strconv"
"testing"
opentracing "github.com/opentracing/opentracing-go"
"github.com/stretchr/testify/assert"
)
func TestTracerPropagationDefaults(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
tracer, _, _ := NewTracer(config)
root := tracer.StartSpan("web.request")
ctx := root.Context()
headers := http.Header{}
// inject the SpanContext
carrier := opentracing.HTTPHeadersCarrier(headers)
err := tracer.Inject(ctx, opentracing.HTTPHeaders, carrier)
assert.Nil(err)
// retrieve the SpanContext
propagated, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
assert.Nil(err)
tCtx, ok := ctx.(SpanContext)
assert.True(ok)
tPropagated, ok := propagated.(SpanContext)
assert.True(ok)
// compare if there is a Context match
assert.Equal(tCtx.traceID, tPropagated.traceID)
assert.Equal(tCtx.spanID, tPropagated.spanID)
// ensure a child can be created
child := tracer.StartSpan("db.query", opentracing.ChildOf(propagated))
tRoot, ok := root.(*Span)
assert.True(ok)
tChild, ok := child.(*Span)
assert.True(ok)
assert.NotEqual(uint64(0), tChild.Span.TraceID)
assert.NotEqual(uint64(0), tChild.Span.SpanID)
assert.Equal(tRoot.Span.SpanID, tChild.Span.ParentID)
assert.Equal(tRoot.Span.TraceID, tChild.Span.ParentID)
tid := strconv.FormatUint(tRoot.Span.TraceID, 10)
pid := strconv.FormatUint(tRoot.Span.SpanID, 10)
// hardcode header names to fail test if defaults are changed
assert.Equal(headers.Get("x-datadog-trace-id"), tid)
assert.Equal(headers.Get("x-datadog-parent-id"), pid)
}
func TestTracerTextMapPropagationHeader(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
config.TextMapPropagator = NewTextMapPropagator("bg-", "tid", "pid")
tracer, _, _ := NewTracer(config)
root := tracer.StartSpan("web.request").SetBaggageItem("item", "x").(*Span)
ctx := root.Context()
headers := http.Header{}
carrier := opentracing.HTTPHeadersCarrier(headers)
err := tracer.Inject(ctx, opentracing.HTTPHeaders, carrier)
assert.Nil(err)
tid := strconv.FormatUint(root.Span.TraceID, 10)
pid := strconv.FormatUint(root.Span.SpanID, 10)
assert.Equal(headers.Get("tid"), tid)
assert.Equal(headers.Get("pid"), pid)
assert.Equal(headers.Get("bg-item"), "x")
}

View file

@ -1,129 +0,0 @@
package opentracing
import (
"errors"
"testing"
"time"
opentracing "github.com/opentracing/opentracing-go"
"github.com/stretchr/testify/assert"
)
func TestSpanBaggage(t *testing.T) {
assert := assert.New(t)
span := NewSpan("web.request")
span.SetBaggageItem("key", "value")
assert.Equal("value", span.BaggageItem("key"))
}
func TestSpanContext(t *testing.T) {
assert := assert.New(t)
span := NewSpan("web.request")
assert.NotNil(span.Context())
}
func TestSpanOperationName(t *testing.T) {
assert := assert.New(t)
span := NewSpan("web.request")
span.SetOperationName("http.request")
assert.Equal("http.request", span.Span.Name)
}
func TestSpanFinish(t *testing.T) {
assert := assert.New(t)
span := NewSpan("web.request")
span.Finish()
assert.True(span.Span.Duration > 0)
}
func TestSpanFinishWithTime(t *testing.T) {
assert := assert.New(t)
finishTime := time.Now().Add(10 * time.Second)
span := NewSpan("web.request")
span.FinishWithOptions(opentracing.FinishOptions{FinishTime: finishTime})
duration := finishTime.UnixNano() - span.Span.Start
assert.Equal(duration, span.Span.Duration)
}
func TestSpanSetTag(t *testing.T) {
assert := assert.New(t)
span := NewSpan("web.request")
span.SetTag("component", "tracer")
assert.Equal("tracer", span.Meta["component"])
span.SetTag("tagInt", 1234)
assert.Equal("1234", span.Meta["tagInt"])
}
func TestSpanSetDatadogTags(t *testing.T) {
assert := assert.New(t)
span := NewSpan("web.request")
span.SetTag("span.type", "http")
span.SetTag("service.name", "db-cluster")
span.SetTag("resource.name", "SELECT * FROM users;")
assert.Equal("http", span.Span.Type)
assert.Equal("db-cluster", span.Span.Service)
assert.Equal("SELECT * FROM users;", span.Span.Resource)
}
func TestSpanSetErrorTag(t *testing.T) {
assert := assert.New(t)
for _, tt := range []struct {
name string // span name
val interface{} // tag value
msg string // error message
typ string // error type
}{
{
name: "error.error",
val: errors.New("some error"),
msg: "some error",
typ: "*errors.errorString",
},
{
name: "error.string",
val: "some string error",
msg: "some string error",
typ: "*errors.errorString",
},
{
name: "error.struct",
val: struct{ N int }{5},
msg: "{5}",
typ: "*errors.errorString",
},
{
name: "error.other",
val: 1,
msg: "1",
typ: "*errors.errorString",
},
{
name: "error.nil",
val: nil,
msg: "",
typ: "",
},
} {
span := NewSpan(tt.name)
span.SetTag(Error, tt.val)
assert.Equal(span.Meta["error.msg"], tt.msg)
assert.Equal(span.Meta["error.type"], tt.typ)
if tt.val != nil {
assert.NotEqual(span.Meta["error.stack"], "")
}
}
}

View file

@ -1,131 +0,0 @@
package opentracing
import (
"testing"
"time"
ddtrace "github.com/DataDog/dd-trace-go/tracer"
opentracing "github.com/opentracing/opentracing-go"
"github.com/stretchr/testify/assert"
)
func TestDefaultTracer(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
tracer, _, _ := NewTracer(config)
tTracer, ok := tracer.(*Tracer)
assert.True(ok)
assert.Equal(tTracer.impl, ddtrace.DefaultTracer)
}
func TestTracerStartSpan(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
tracer, _, _ := NewTracer(config)
span, ok := tracer.StartSpan("web.request").(*Span)
assert.True(ok)
assert.NotEqual(uint64(0), span.Span.TraceID)
assert.NotEqual(uint64(0), span.Span.SpanID)
assert.Equal(uint64(0), span.Span.ParentID)
assert.Equal("web.request", span.Span.Name)
assert.Equal("opentracing.test", span.Span.Service)
assert.NotNil(span.Span.Tracer())
}
func TestTracerStartChildSpan(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
tracer, _, _ := NewTracer(config)
root := tracer.StartSpan("web.request")
child := tracer.StartSpan("db.query", opentracing.ChildOf(root.Context()))
tRoot, ok := root.(*Span)
assert.True(ok)
tChild, ok := child.(*Span)
assert.True(ok)
assert.NotEqual(uint64(0), tChild.Span.TraceID)
assert.NotEqual(uint64(0), tChild.Span.SpanID)
assert.Equal(tRoot.Span.SpanID, tChild.Span.ParentID)
assert.Equal(tRoot.Span.TraceID, tChild.Span.ParentID)
}
func TestTracerBaggagePropagation(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
tracer, _, _ := NewTracer(config)
root := tracer.StartSpan("web.request")
root.SetBaggageItem("key", "value")
child := tracer.StartSpan("db.query", opentracing.ChildOf(root.Context()))
context, ok := child.Context().(SpanContext)
assert.True(ok)
assert.Equal("value", context.baggage["key"])
}
func TestTracerBaggageImmutability(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
tracer, _, _ := NewTracer(config)
root := tracer.StartSpan("web.request")
root.SetBaggageItem("key", "value")
child := tracer.StartSpan("db.query", opentracing.ChildOf(root.Context()))
child.SetBaggageItem("key", "changed!")
parentContext, ok := root.Context().(SpanContext)
assert.True(ok)
childContext, ok := child.Context().(SpanContext)
assert.True(ok)
assert.Equal("value", parentContext.baggage["key"])
assert.Equal("changed!", childContext.baggage["key"])
}
func TestTracerSpanTags(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
tracer, _, _ := NewTracer(config)
tag := opentracing.Tag{Key: "key", Value: "value"}
span, ok := tracer.StartSpan("web.request", tag).(*Span)
assert.True(ok)
assert.Equal("value", span.Span.Meta["key"])
}
func TestTracerSpanGlobalTags(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
config.GlobalTags["key"] = "value"
tracer, _, _ := NewTracer(config)
span := tracer.StartSpan("web.request").(*Span)
assert.Equal("value", span.Span.Meta["key"])
child := tracer.StartSpan("db.query", opentracing.ChildOf(span.Context())).(*Span)
assert.Equal("value", child.Span.Meta["key"])
}
func TestTracerSpanStartTime(t *testing.T) {
assert := assert.New(t)
config := NewConfiguration()
tracer, _, _ := NewTracer(config)
startTime := time.Now().Add(-10 * time.Second)
span, ok := tracer.StartSpan("web.request", opentracing.StartTime(startTime)).(*Span)
assert.True(ok)
assert.Equal(startTime.UnixNano(), span.Span.Start)
}

View file

@ -1,105 +0,0 @@
package tracer
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
const (
testInitSize = 2
testMaxSize = 5
)
func TestSpanBufferPushOne(t *testing.T) {
assert := assert.New(t)
buffer := newSpanBuffer(newTracerChans(), testInitSize, testMaxSize)
assert.NotNil(buffer)
assert.Len(buffer.spans, 0)
traceID := NextSpanID()
root := NewSpan("name1", "a-service", "a-resource", traceID, traceID, 0, nil)
root.buffer = buffer
buffer.Push(root)
assert.Len(buffer.spans, 1, "there is one span in the buffer")
assert.Equal(root, buffer.spans[0], "the span is the one pushed before")
root.Finish()
select {
case trace := <-buffer.channels.trace:
assert.Len(trace, 1, "there was a trace in the channel")
assert.Equal(root, trace[0], "the trace in the channel is the one pushed before")
assert.Equal(0, buffer.Len(), "no more spans in the buffer")
case err := <-buffer.channels.err:
assert.Fail("unexpected error:", err.Error())
t.Logf("buffer: %v", buffer)
}
}
func TestSpanBufferPushNoFinish(t *testing.T) {
assert := assert.New(t)
buffer := newSpanBuffer(newTracerChans(), testInitSize, testMaxSize)
assert.NotNil(buffer)
assert.Len(buffer.spans, 0)
traceID := NextSpanID()
root := NewSpan("name1", "a-service", "a-resource", traceID, traceID, 0, nil)
root.buffer = buffer
buffer.Push(root)
assert.Len(buffer.spans, 1, "there is one span in the buffer")
assert.Equal(root, buffer.spans[0], "the span is the one pushed before")
select {
case <-buffer.channels.trace:
assert.Fail("span was not finished, should not be flushed")
t.Logf("buffer: %v", buffer)
case err := <-buffer.channels.err:
assert.Fail("unexpected error:", err.Error())
t.Logf("buffer: %v", buffer)
case <-time.After(time.Second / 10):
t.Logf("expected timeout, nothing should show up in buffer as the trace is not finished")
}
}
func TestSpanBufferPushSeveral(t *testing.T) {
assert := assert.New(t)
buffer := newSpanBuffer(newTracerChans(), testInitSize, testMaxSize)
assert.NotNil(buffer)
assert.Len(buffer.spans, 0)
traceID := NextSpanID()
root := NewSpan("name1", "a-service", "a-resource", traceID, traceID, 0, nil)
span2 := NewSpan("name2", "a-service", "a-resource", NextSpanID(), traceID, root.SpanID, nil)
span3 := NewSpan("name3", "a-service", "a-resource", NextSpanID(), traceID, root.SpanID, nil)
span3a := NewSpan("name3", "a-service", "a-resource", NextSpanID(), traceID, span3.SpanID, nil)
spans := []*Span{root, span2, span3, span3a}
for i, span := range spans {
span.buffer = buffer
buffer.Push(span)
assert.Len(buffer.spans, i+1, "there is one more span in the buffer")
assert.Equal(span, buffer.spans[i], "the span is the one pushed before")
}
for _, span := range spans {
span.Finish()
}
select {
case trace := <-buffer.channels.trace:
assert.Len(trace, 4, "there was one trace with the right number of spans in the channel")
for _, span := range spans {
assert.Contains(trace, span, "the trace contains the spans")
}
case err := <-buffer.channels.err:
assert.Fail("unexpected error:", err.Error())
}
}

View file

@ -1,117 +0,0 @@
package tracer
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestPushTrace(t *testing.T) {
assert := assert.New(t)
channels := newTracerChans()
trace := []*Span{
&Span{
Name: "pylons.request",
Service: "pylons",
Resource: "/",
},
&Span{
Name: "pylons.request",
Service: "pylons",
Resource: "/foo",
},
}
channels.pushTrace(trace)
assert.Len(channels.trace, 1, "there should be data in channel")
assert.Len(channels.traceFlush, 0, "no flush requested yet")
pushed := <-channels.trace
assert.Equal(trace, pushed)
many := traceChanLen/2 + 1
for i := 0; i < many; i++ {
channels.pushTrace(make([]*Span, i))
}
assert.Len(channels.trace, many, "all traces should be in the channel, not yet blocking")
assert.Len(channels.traceFlush, 1, "a trace flush should have been requested")
for i := 0; i < cap(channels.trace); i++ {
channels.pushTrace(make([]*Span, i))
}
assert.Len(channels.trace, traceChanLen, "buffer should be full")
assert.NotEqual(0, len(channels.err), "there should be an error logged")
err := <-channels.err
assert.Equal(&errorTraceChanFull{Len: traceChanLen}, err)
}
func TestPushService(t *testing.T) {
assert := assert.New(t)
channels := newTracerChans()
service := Service{
Name: "redis-master",
App: "redis",
AppType: "db",
}
channels.pushService(service)
assert.Len(channels.service, 1, "there should be data in channel")
assert.Len(channels.serviceFlush, 0, "no flush requested yet")
pushed := <-channels.service
assert.Equal(service, pushed)
many := serviceChanLen/2 + 1
for i := 0; i < many; i++ {
channels.pushService(Service{
Name: fmt.Sprintf("service%d", i),
App: "custom",
AppType: "web",
})
}
assert.Len(channels.service, many, "all services should be in the channel, not yet blocking")
assert.Len(channels.serviceFlush, 1, "a service flush should have been requested")
for i := 0; i < cap(channels.service); i++ {
channels.pushService(Service{
Name: fmt.Sprintf("service%d", i),
App: "custom",
AppType: "web",
})
}
assert.Len(channels.service, serviceChanLen, "buffer should be full")
assert.NotEqual(0, len(channels.err), "there should be an error logged")
err := <-channels.err
assert.Equal(&errorServiceChanFull{Len: serviceChanLen}, err)
}
func TestPushErr(t *testing.T) {
assert := assert.New(t)
channels := newTracerChans()
err := fmt.Errorf("ooops")
channels.pushErr(err)
assert.Len(channels.err, 1, "there should be data in channel")
assert.Len(channels.errFlush, 0, "no flush requested yet")
pushed := <-channels.err
assert.Equal(err, pushed)
many := errChanLen/2 + 1
for i := 0; i < many; i++ {
channels.pushErr(fmt.Errorf("err %d", i))
}
assert.Len(channels.err, many, "all errs should be in the channel, not yet blocking")
assert.Len(channels.errFlush, 1, "a err flush should have been requested")
for i := 0; i < cap(channels.err); i++ {
channels.pushErr(fmt.Errorf("err %d", i))
}
// if we reach this, means pushErr is not blocking, which is what we want to double-check
}

View file

@ -1,69 +0,0 @@
package tracer
import (
"testing"
"context"
"github.com/stretchr/testify/assert"
)
func TestContextWithSpanDefault(t *testing.T) {
assert := assert.New(t)
// create a new context with a span
span := SpanFromContextDefault(nil)
assert.NotNil(span)
ctx := context.Background()
assert.NotNil(SpanFromContextDefault(ctx))
}
func TestSpanFromContext(t *testing.T) {
assert := assert.New(t)
// create a new context with a span
ctx := context.Background()
tracer := NewTracer()
expectedSpan := tracer.NewRootSpan("pylons.request", "pylons", "/")
ctx = ContextWithSpan(ctx, expectedSpan)
span, ok := SpanFromContext(ctx)
assert.True(ok)
assert.Equal(expectedSpan, span)
}
func TestSpanFromContextNil(t *testing.T) {
assert := assert.New(t)
// create a context without a span
ctx := context.Background()
span, ok := SpanFromContext(ctx)
assert.False(ok)
assert.Nil(span)
span, ok = SpanFromContext(nil)
assert.False(ok)
assert.Nil(span)
}
func TestSpanMissingParent(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
// assuming we're in an inner function and we
// forget the nil or ok checks
ctx := context.Background()
span, _ := SpanFromContext(ctx)
// span is nil according to the API
child := tracer.NewChildSpan("redis.command", span)
child.Finish()
// the child is finished but it's not recorded in
// the tracer buffer because the service is missing
assert.True(child.Duration > 0)
assert.Equal(1, len(tracer.channels.trace))
}

View file

@ -1,114 +0,0 @@
package tracer
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
"github.com/ugorji/go/codec"
)
func TestEncoderContentType(t *testing.T) {
assert := assert.New(t)
testCases := []struct {
encoder Encoder
contentType string
}{
{newJSONEncoder(), "application/json"},
{newMsgpackEncoder(), "application/msgpack"},
}
for _, tc := range testCases {
assert.Equal(tc.contentType, tc.encoder.ContentType())
}
}
func TestJSONEncoding(t *testing.T) {
assert := assert.New(t)
testCases := []struct {
traces int
size int
}{
{1, 1},
{3, 1},
{1, 3},
{3, 3},
}
for _, tc := range testCases {
payload := getTestTrace(tc.traces, tc.size)
encoder := newJSONEncoder()
err := encoder.EncodeTraces(payload)
assert.Nil(err)
// decode to check the right encoding
var traces [][]*Span
dec := json.NewDecoder(encoder.buffer)
err = dec.Decode(&traces)
assert.Nil(err)
assert.Len(traces, tc.traces)
for _, trace := range traces {
assert.Len(trace, tc.size)
span := trace[0]
assert.Equal(uint64(42), span.TraceID)
assert.Equal(uint64(52), span.SpanID)
assert.Equal(uint64(42), span.ParentID)
assert.Equal("web", span.Type)
assert.Equal("high.throughput", span.Service)
assert.Equal("sending.events", span.Name)
assert.Equal("SEND /data", span.Resource)
assert.Equal(int64(1481215590883401105), span.Start)
assert.Equal(int64(1000000000), span.Duration)
assert.Equal("192.168.0.1", span.Meta["http.host"])
assert.Equal(float64(41.99), span.Metrics["http.monitor"])
}
}
}
func TestMsgpackEncoding(t *testing.T) {
assert := assert.New(t)
testCases := []struct {
traces int
size int
}{
{1, 1},
{3, 1},
{1, 3},
{3, 3},
}
for _, tc := range testCases {
payload := getTestTrace(tc.traces, tc.size)
encoder := newMsgpackEncoder()
err := encoder.EncodeTraces(payload)
assert.Nil(err)
// decode to check the right encoding
var traces [][]*Span
var mh codec.MsgpackHandle
dec := codec.NewDecoder(encoder.buffer, &mh)
err = dec.Decode(&traces)
assert.Nil(err)
assert.Len(traces, tc.traces)
for _, trace := range traces {
assert.Len(trace, tc.size)
span := trace[0]
assert.Equal(uint64(42), span.TraceID)
assert.Equal(uint64(52), span.SpanID)
assert.Equal(uint64(42), span.ParentID)
assert.Equal("web", span.Type)
assert.Equal("high.throughput", span.Service)
assert.Equal("sending.events", span.Name)
assert.Equal("SEND /data", span.Resource)
assert.Equal(int64(1481215590883401105), span.Start)
assert.Equal(int64(1000000000), span.Duration)
assert.Equal("192.168.0.1", span.Meta["http.host"])
assert.Equal(float64(41.99), span.Metrics["http.monitor"])
}
}
}

View file

@ -1,98 +0,0 @@
package tracer
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestErrorSpanBufFull(t *testing.T) {
assert := assert.New(t)
err := &errorSpanBufFull{Len: 42}
assert.Equal("span buffer is full (length: 42)", err.Error())
assert.Equal("ErrorSpanBufFull", errorKey(err))
}
func TestErrorTraceChanFull(t *testing.T) {
assert := assert.New(t)
err := &errorTraceChanFull{Len: 42}
assert.Equal("trace channel is full (length: 42)", err.Error())
assert.Equal("ErrorTraceChanFull", errorKey(err))
}
func TestErrorServiceChanFull(t *testing.T) {
assert := assert.New(t)
err := &errorServiceChanFull{Len: 42}
assert.Equal("service channel is full (length: 42)", err.Error())
assert.Equal("ErrorServiceChanFull", errorKey(err))
}
func TestErrorTraceIDMismatch(t *testing.T) {
assert := assert.New(t)
err := &errorTraceIDMismatch{Expected: 42, Actual: 65535}
assert.Equal("trace ID mismatch (expected: 2a actual: ffff)", err.Error())
assert.Equal("ErrorTraceIDMismatch", errorKey(err))
}
func TestErrorNoSpanBuf(t *testing.T) {
assert := assert.New(t)
err := &errorNoSpanBuf{SpanName: "do"}
assert.Equal("no span buffer (span name: 'do')", err.Error())
}
func TestErrorFlushLostTraces(t *testing.T) {
assert := assert.New(t)
err := &errorFlushLostTraces{Nb: 100}
assert.Equal("unable to flush traces, lost 100 traces", err.Error())
}
func TestErrorFlushLostServices(t *testing.T) {
assert := assert.New(t)
err := &errorFlushLostServices{Nb: 100}
assert.Equal("unable to flush services, lost 100 services", err.Error())
}
func TestErrorKey(t *testing.T) {
assert := assert.New(t)
assert.Equal("this is something unexpected", errorKey(fmt.Errorf("this is something unexpected")))
assert.Equal("", errorKey(nil))
}
func TestAggregateErrors(t *testing.T) {
assert := assert.New(t)
errChan := make(chan error, 100)
errChan <- &errorSpanBufFull{Len: 1000}
errChan <- &errorSpanBufFull{Len: 1000}
errChan <- &errorSpanBufFull{Len: 1000}
errChan <- &errorSpanBufFull{Len: 1000}
errChan <- &errorFlushLostTraces{Nb: 42}
errChan <- &errorTraceIDMismatch{Expected: 42, Actual: 1}
errChan <- &errorTraceIDMismatch{Expected: 42, Actual: 4095}
errs := aggregateErrors(errChan)
assert.Equal(map[string]errorSummary{
"ErrorSpanBufFull": errorSummary{
Count: 4,
Example: "span buffer is full (length: 1000)",
},
"ErrorTraceIDMismatch": errorSummary{
Count: 2,
Example: "trace ID mismatch (expected: 2a actual: fff)",
},
"ErrorFlushLostTraces": errorSummary{
Count: 1,
Example: "unable to flush traces, lost 42 traces",
},
}, errs)
}

View file

@ -1,73 +0,0 @@
package tracer_test
import (
"context"
"fmt"
"io"
"log"
"net/http"
"os"
"github.com/DataDog/dd-trace-go/tracer"
)
func saveFile(ctx context.Context, path string, r io.Reader) error {
// Start a new span that is the child of the span stored in the context, and
// attach it to the current context. If the context has no span, it will
// return an empty root span.
span, ctx := tracer.NewChildSpanWithContext("filestore.saveFile", ctx)
defer span.Finish()
// save the file contents.
file, err := os.Create(path)
if err != nil {
span.SetError(err)
return err
}
defer file.Close()
_, err = io.Copy(file, r)
span.SetError(err)
return err
}
func saveFileHandler(w http.ResponseWriter, r *http.Request) {
// the name of the operation we're measuring
name := "http.request"
service := "example-filestore"
resource := "/saveFile"
// This is the main entry point of our application, so we create a root span
// that includes the service and resource name.
span := tracer.NewRootSpan(name, service, resource)
defer span.Finish()
// Add the span to the request's context so we can pass the tracing information
// down the stack.
ctx := span.Context(r.Context())
// Do the work.
err := saveFile(ctx, "/tmp/example", r.Body)
span.SetError(err) // no-op if err == nil
if err != nil {
http.Error(w, fmt.Sprintf("error saving file! %s", err), 500)
return
}
w.Write([]byte("saved file!"))
}
// Tracing the hierarchy of spans in a request is a key part of tracing. This, for example,
// let's a developer associate all of the database calls in a web request. As of Go 1.7,
// the standard way of doing this is with the context package. Along with supporting
// deadlines, cancellation signals and more, Contexts are perfect for passing (optional)
// telemetry data through your stack.
//
// Read more about contexts here: https://golang.org/pkg/context/
//
// Here is an example illustrating how to pass tracing data with contexts.
func Example_context() {
http.HandleFunc("/saveFile", saveFileHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}

View file

@ -1,23 +0,0 @@
package tracer_test
import (
"net/http"
"github.com/DataDog/dd-trace-go/tracer"
)
func Example() {
span := tracer.NewRootSpan("http.client.request", "example.com", "/user/{id}")
defer span.Finish()
url := "http://example.com/user/123"
resp, err := http.Get(url)
if err != nil {
span.SetError(err)
return
}
span.SetMeta("http.status", resp.Status)
span.SetMeta("http.url", url)
}

View file

@ -1,289 +0,0 @@
package tracer
import (
"context"
"errors"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/DataDog/dd-trace-go/tracer/ext"
)
func TestSpanStart(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// a new span sets the Start after the initialization
assert.NotEqual(int64(0), span.Start)
}
func TestSpanString(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// don't bother checking the contents, just make sure it works.
assert.NotEqual("", span.String())
span.Finish()
assert.NotEqual("", span.String())
}
func TestSpanSetMeta(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// check the map is properly initialized
span.SetMeta("status.code", "200")
assert.Equal("200", span.Meta["status.code"])
// operating on a finished span is a no-op
nMeta := len(span.Meta)
span.Finish()
span.SetMeta("finished.test", "true")
assert.Equal(len(span.Meta), nMeta)
assert.Equal(span.Meta["finished.test"], "")
}
func TestSpanSetMetas(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
span.SetSamplingPriority(0) // avoid interferences with "_sampling_priority_v1" meta
metas := map[string]string{
"error.msg": "Something wrong",
"error.type": "*errors.errorString",
"status.code": "200",
"system.pid": "29176",
}
extraMetas := map[string]string{
"custom.1": "something custom",
"custom.2": "something even more special",
}
nopMetas := map[string]string{
"nopKey1": "nopValue1",
"nopKey2": "nopValue2",
}
// check the map is properly initialized
span.SetMetas(metas)
assert.Equal(len(metas), len(span.Meta))
for k := range metas {
assert.Equal(metas[k], span.Meta[k])
}
// check a second call adds the new metas, but does not remove old ones
span.SetMetas(extraMetas)
assert.Equal(len(metas)+len(extraMetas), len(span.Meta))
for k := range extraMetas {
assert.Equal(extraMetas[k], span.Meta[k])
}
assert.Equal(span.Meta["status.code"], "200")
// operating on a finished span is a no-op
span.Finish()
span.SetMetas(nopMetas)
assert.Equal(len(metas)+len(extraMetas), len(span.Meta))
for k := range nopMetas {
assert.Equal("", span.Meta[k])
}
}
func TestSpanSetMetric(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// check the map is properly initialized
span.SetMetric("bytes", 1024.42)
assert.Equal(1, len(span.Metrics))
assert.Equal(1024.42, span.Metrics["bytes"])
// operating on a finished span is a no-op
span.Finish()
span.SetMetric("finished.test", 1337)
assert.Equal(1, len(span.Metrics))
assert.Equal(0.0, span.Metrics["finished.test"])
}
func TestSpanError(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// check the error is set in the default meta
err := errors.New("Something wrong")
span.SetError(err)
assert.Equal(int32(1), span.Error)
assert.Equal("Something wrong", span.Meta["error.msg"])
assert.Equal("*errors.errorString", span.Meta["error.type"])
assert.NotEqual("", span.Meta["error.stack"])
// operating on a finished span is a no-op
span = tracer.NewRootSpan("flask.request", "flask", "/")
nMeta := len(span.Meta)
span.Finish()
span.SetError(err)
assert.Equal(int32(0), span.Error)
assert.Equal(nMeta, len(span.Meta))
assert.Equal("", span.Meta["error.msg"])
assert.Equal("", span.Meta["error.type"])
assert.Equal("", span.Meta["error.stack"])
}
func TestSpanError_Typed(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// check the error is set in the default meta
err := &boomError{}
span.SetError(err)
assert.Equal(int32(1), span.Error)
assert.Equal("boom", span.Meta["error.msg"])
assert.Equal("*tracer.boomError", span.Meta["error.type"])
assert.NotEqual("", span.Meta["error.stack"])
}
func TestEmptySpan(t *testing.T) {
// ensure the empty span won't crash the app
var span Span
span.SetMeta("a", "b")
span.SetError(nil)
span.Finish()
var s *Span
s.SetMeta("a", "b")
s.SetError(nil)
s.Finish()
}
func TestSpanErrorNil(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// don't set the error if it's nil
nMeta := len(span.Meta)
span.SetError(nil)
assert.Equal(int32(0), span.Error)
assert.Equal(nMeta, len(span.Meta))
}
func TestSpanFinish(t *testing.T) {
assert := assert.New(t)
wait := time.Millisecond * 2
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// the finish should set finished and the duration
time.Sleep(wait)
span.Finish()
assert.True(span.Duration > int64(wait))
assert.True(span.finished)
}
func TestSpanFinishTwice(t *testing.T) {
assert := assert.New(t)
wait := time.Millisecond * 2
tracer, _ := getTestTracer()
defer tracer.Stop()
assert.Len(tracer.channels.trace, 0)
// the finish must be idempotent
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
time.Sleep(wait)
span.Finish()
assert.Len(tracer.channels.trace, 1)
previousDuration := span.Duration
time.Sleep(wait)
span.Finish()
assert.Equal(previousDuration, span.Duration)
assert.Len(tracer.channels.trace, 1)
}
func TestSpanContext(t *testing.T) {
ctx := context.Background()
_, ok := SpanFromContext(ctx)
assert.False(t, ok)
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
ctx = span.Context(ctx)
s2, ok := SpanFromContext(ctx)
assert.True(t, ok)
assert.Equal(t, span.SpanID, s2.SpanID)
}
// Prior to a bug fix, this failed when running `go test -race`
func TestSpanModifyWhileFlushing(t *testing.T) {
tracer, _ := getTestTracer()
defer tracer.Stop()
done := make(chan struct{})
go func() {
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
span.Finish()
// It doesn't make much sense to update the span after it's been finished,
// but an error in a user's code could lead to this.
span.SetMeta("race_test", "true")
span.SetMetric("race_test2", 133.7)
span.SetMetrics("race_test3", 133.7)
span.SetError(errors.New("t"))
done <- struct{}{}
}()
run := true
for run {
select {
case <-done:
run = false
default:
tracer.flushTraces()
}
}
}
func TestSpanSamplingPriority(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
span := tracer.NewRootSpan("my.name", "my.service", "my.resource")
assert.Equal(0.0, span.Metrics["_sampling_priority_v1"], "default sampling priority if undefined is 0")
assert.False(span.HasSamplingPriority(), "by default, sampling priority is undefined")
assert.Equal(0, span.GetSamplingPriority(), "default sampling priority for root spans is 0")
childSpan := tracer.NewChildSpan("my.child", span)
assert.Equal(span.Metrics["_sampling_priority_v1"], childSpan.Metrics["_sampling_priority_v1"])
assert.Equal(span.HasSamplingPriority(), childSpan.HasSamplingPriority())
assert.Equal(span.GetSamplingPriority(), childSpan.GetSamplingPriority())
for _, priority := range []int{
ext.PriorityUserReject,
ext.PriorityAutoReject,
ext.PriorityAutoKeep,
ext.PriorityUserKeep,
999, // not used yet, but we should allow it
} {
span.SetSamplingPriority(priority)
assert.True(span.HasSamplingPriority())
assert.Equal(priority, span.GetSamplingPriority())
childSpan = tracer.NewChildSpan("my.child", span)
assert.Equal(span.Metrics["_sampling_priority_v1"], childSpan.Metrics["_sampling_priority_v1"])
assert.Equal(span.HasSamplingPriority(), childSpan.HasSamplingPriority())
assert.Equal(span.GetSamplingPriority(), childSpan.GetSamplingPriority())
}
}
type boomError struct{}
func (e *boomError) Error() string { return "boom" }

View file

@ -1,30 +0,0 @@
package tracer
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)
func BenchmarkNormalTimeNow(b *testing.B) {
for n := 0; n < b.N; n++ {
lowPrecisionNow()
}
}
func BenchmarkHighPrecisionTime(b *testing.B) {
for n := 0; n < b.N; n++ {
highPrecisionNow()
}
}
func TestHighPrecisionTimerIsMoreAccurate(t *testing.T) {
startLow := lowPrecisionNow()
startHigh := highPrecisionNow()
stopHigh := highPrecisionNow()
for stopHigh == startHigh {
stopHigh = highPrecisionNow()
}
stopLow := lowPrecisionNow()
assert.Equal(t, int64(0), stopLow-startLow)
}

View file

@ -1,648 +0,0 @@
package tracer
import (
"context"
"fmt"
"github.com/DataDog/dd-trace-go/tracer/ext"
"net/http"
"os"
"strconv"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestDefaultTracer(t *testing.T) {
assert := assert.New(t)
var wg sync.WaitGroup
// the default client must be available
assert.NotNil(DefaultTracer)
// package free functions must proxy the calls to the
// default client
root := NewRootSpan("pylons.request", "pylons", "/")
NewChildSpan("pylons.request", root)
wg.Add(2)
go func() {
for i := 0; i < 1000; i++ {
Disable()
Enable()
}
wg.Done()
}()
go func() {
for i := 0; i < 1000; i++ {
_ = DefaultTracer.Enabled()
}
wg.Done()
}()
wg.Wait()
}
func TestNewSpan(t *testing.T) {
assert := assert.New(t)
// the tracer must create root spans
tracer := NewTracer()
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
assert.Equal(uint64(0), span.ParentID)
assert.Equal("pylons", span.Service)
assert.Equal("pylons.request", span.Name)
assert.Equal("/", span.Resource)
}
func TestNewSpanFromContextNil(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
child := tracer.NewChildSpanFromContext("abc", nil)
assert.Equal("abc", child.Name)
assert.Equal("", child.Service)
child = tracer.NewChildSpanFromContext("def", context.Background())
assert.Equal("def", child.Name)
assert.Equal("", child.Service)
}
func TestNewChildSpanWithContext(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
// nil context
span, ctx := tracer.NewChildSpanWithContext("abc", nil)
assert.Equal("abc", span.Name)
assert.Equal("", span.Service)
assert.Equal(span.ParentID, span.SpanID) // it should be a root span
assert.Equal(span.Tracer(), tracer)
// the returned ctx should contain the created span
assert.NotNil(ctx)
ctxSpan, ok := SpanFromContext(ctx)
assert.True(ok)
assert.Equal(span, ctxSpan)
// context without span
span, ctx = tracer.NewChildSpanWithContext("abc", context.Background())
assert.Equal("abc", span.Name)
assert.Equal("", span.Service)
assert.Equal(span.ParentID, span.SpanID) // it should be a root span
// the returned ctx should contain the created span
assert.NotNil(ctx)
ctxSpan, ok = SpanFromContext(ctx)
assert.True(ok)
assert.Equal(span, ctxSpan)
// context with span
parent := tracer.NewRootSpan("pylons.request", "pylons", "/")
parentCTX := ContextWithSpan(context.Background(), parent)
span, ctx = tracer.NewChildSpanWithContext("def", parentCTX)
assert.Equal("def", span.Name)
assert.Equal("pylons", span.Service)
assert.Equal(parent.Service, span.Service)
// the created span should be a child of the parent span
assert.Equal(span.ParentID, parent.SpanID)
// the returned ctx should contain the created span
assert.NotNil(ctx)
ctxSpan, ok = SpanFromContext(ctx)
assert.True(ok)
assert.Equal(ctxSpan, span)
}
func TestNewSpanFromContext(t *testing.T) {
assert := assert.New(t)
// the tracer must create child spans
tracer := NewTracer()
parent := tracer.NewRootSpan("pylons.request", "pylons", "/")
ctx := ContextWithSpan(context.Background(), parent)
child := tracer.NewChildSpanFromContext("redis.command", ctx)
// ids and services are inherited
assert.Equal(parent.SpanID, child.ParentID)
assert.Equal(parent.TraceID, child.TraceID)
assert.Equal(parent.Service, child.Service)
// the resource is not inherited and defaults to the name
assert.Equal("redis.command", child.Resource)
// the tracer instance is the same
assert.Equal(tracer, parent.tracer)
assert.Equal(tracer, child.tracer)
}
func TestNewSpanChild(t *testing.T) {
assert := assert.New(t)
// the tracer must create child spans
tracer := NewTracer()
parent := tracer.NewRootSpan("pylons.request", "pylons", "/")
child := tracer.NewChildSpan("redis.command", parent)
// ids and services are inherited
assert.Equal(parent.SpanID, child.ParentID)
assert.Equal(parent.TraceID, child.TraceID)
assert.Equal(parent.Service, child.Service)
// the resource is not inherited and defaults to the name
assert.Equal("redis.command", child.Resource)
// the tracer instance is the same
assert.Equal(tracer, parent.tracer)
assert.Equal(tracer, child.tracer)
}
func TestNewRootSpanHasPid(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
root := tracer.NewRootSpan("pylons.request", "pylons", "/")
assert.Equal(strconv.Itoa(os.Getpid()), root.GetMeta(ext.Pid))
}
func TestNewChildHasNoPid(t *testing.T) {
assert := assert.New(t)
tracer := NewTracer()
root := tracer.NewRootSpan("pylons.request", "pylons", "/")
child := tracer.NewChildSpan("redis.command", root)
assert.Equal("", child.GetMeta(ext.Pid))
}
func TestTracerDisabled(t *testing.T) {
assert := assert.New(t)
// disable the tracer and be sure that the span is not added
tracer := NewTracer()
tracer.SetEnabled(false)
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
span.Finish()
assert.Len(tracer.channels.trace, 0)
}
func TestTracerEnabledAgain(t *testing.T) {
assert := assert.New(t)
// disable the tracer and enable it again
tracer := NewTracer()
tracer.SetEnabled(false)
preSpan := tracer.NewRootSpan("pylons.request", "pylons", "/")
preSpan.Finish()
assert.Len(tracer.channels.trace, 0)
tracer.SetEnabled(true)
postSpan := tracer.NewRootSpan("pylons.request", "pylons", "/")
postSpan.Finish()
assert.Len(tracer.channels.trace, 1)
}
func TestTracerSampler(t *testing.T) {
assert := assert.New(t)
sampleRate := 0.5
tracer := NewTracer()
tracer.SetSampleRate(sampleRate)
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
// The span might be sampled or not, we don't know, but at least it should have the sample rate metric
assert.Equal(sampleRate, span.Metrics[sampleRateMetricKey])
}
func TestTracerEdgeSampler(t *testing.T) {
assert := assert.New(t)
// a sample rate of 0 should sample nothing
tracer0 := NewTracer()
tracer0.SetSampleRate(0)
// a sample rate of 1 should sample everything
tracer1 := NewTracer()
tracer1.SetSampleRate(1)
count := traceChanLen / 3
for i := 0; i < count; i++ {
span0 := tracer0.NewRootSpan("pylons.request", "pylons", "/")
span0.Finish()
span1 := tracer1.NewRootSpan("pylons.request", "pylons", "/")
span1.Finish()
}
assert.Len(tracer0.channels.trace, 0)
assert.Len(tracer1.channels.trace, count)
tracer0.Stop()
tracer1.Stop()
}
func TestTracerConcurrent(t *testing.T) {
assert := assert.New(t)
tracer, transport := getTestTracer()
defer tracer.Stop()
// Wait for three different goroutines that should create
// three different traces with one child each
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
tracer.NewRootSpan("pylons.request", "pylons", "/").Finish()
}()
go func() {
defer wg.Done()
tracer.NewRootSpan("pylons.request", "pylons", "/home").Finish()
}()
go func() {
defer wg.Done()
tracer.NewRootSpan("pylons.request", "pylons", "/trace").Finish()
}()
wg.Wait()
tracer.ForceFlush()
traces := transport.Traces()
assert.Len(traces, 3)
assert.Len(traces[0], 1)
assert.Len(traces[1], 1)
assert.Len(traces[2], 1)
}
func TestTracerParentFinishBeforeChild(t *testing.T) {
assert := assert.New(t)
tracer, transport := getTestTracer()
defer tracer.Stop()
// Testing an edge case: a child refers to a parent that is already closed.
parent := tracer.NewRootSpan("pylons.request", "pylons", "/")
parent.Finish()
tracer.ForceFlush()
traces := transport.Traces()
assert.Len(traces, 1)
assert.Len(traces[0], 1)
assert.Equal(parent, traces[0][0])
child := tracer.NewChildSpan("redis.command", parent)
child.Finish()
tracer.ForceFlush()
traces = transport.Traces()
assert.Len(traces, 1)
assert.Len(traces[0], 1)
assert.Equal(child, traces[0][0])
assert.Equal(parent.SpanID, traces[0][0].ParentID, "child should refer to parent, even if they have been flushed separately")
}
func TestTracerConcurrentMultipleSpans(t *testing.T) {
assert := assert.New(t)
tracer, transport := getTestTracer()
defer tracer.Stop()
// Wait for two different goroutines that should create
// two traces with two children each
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
parent := tracer.NewRootSpan("pylons.request", "pylons", "/")
child := tracer.NewChildSpan("redis.command", parent)
child.Finish()
parent.Finish()
}()
go func() {
defer wg.Done()
parent := tracer.NewRootSpan("pylons.request", "pylons", "/")
child := tracer.NewChildSpan("redis.command", parent)
child.Finish()
parent.Finish()
}()
wg.Wait()
tracer.ForceFlush()
traces := transport.Traces()
assert.Len(traces, 2)
assert.Len(traces[0], 2)
assert.Len(traces[1], 2)
}
func TestTracerAtomicFlush(t *testing.T) {
assert := assert.New(t)
tracer, transport := getTestTracer()
defer tracer.Stop()
// Make sure we don't flush partial bits of traces
root := tracer.NewRootSpan("pylons.request", "pylons", "/")
span := tracer.NewChildSpan("redis.command", root)
span1 := tracer.NewChildSpan("redis.command.1", span)
span2 := tracer.NewChildSpan("redis.command.2", span)
span.Finish()
span1.Finish()
span2.Finish()
tracer.ForceFlush()
traces := transport.Traces()
assert.Len(traces, 0, "nothing should be flushed now as span2 is not finished yet")
root.Finish()
tracer.ForceFlush()
traces = transport.Traces()
assert.Len(traces, 1)
assert.Len(traces[0], 4, "all spans should show up at once")
}
func TestTracerServices(t *testing.T) {
assert := assert.New(t)
tracer, transport := getTestTracer()
tracer.SetServiceInfo("svc1", "a", "b")
tracer.SetServiceInfo("svc2", "c", "d")
tracer.SetServiceInfo("svc1", "e", "f")
tracer.Stop()
assert.Len(transport.services, 2)
svc1 := transport.services["svc1"]
assert.NotNil(svc1)
assert.Equal("svc1", svc1.Name)
assert.Equal("e", svc1.App)
assert.Equal("f", svc1.AppType)
svc2 := transport.services["svc2"]
assert.NotNil(svc2)
assert.Equal("svc2", svc2.Name)
assert.Equal("c", svc2.App)
assert.Equal("d", svc2.AppType)
}
func TestTracerServicesDisabled(t *testing.T) {
assert := assert.New(t)
tracer, transport := getTestTracer()
tracer.SetEnabled(false)
tracer.SetServiceInfo("svc1", "a", "b")
tracer.Stop()
assert.Len(transport.services, 0)
}
func TestTracerMeta(t *testing.T) {
assert := assert.New(t)
var nilTracer *Tracer
nilTracer.SetMeta("key", "value")
assert.Nil(nilTracer.getAllMeta(), "nil tracer should return nil meta")
tracer, _ := getTestTracer()
defer tracer.Stop()
assert.Nil(tracer.getAllMeta(), "by default, no meta")
tracer.SetMeta("env", "staging")
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
assert.Equal("staging", span.GetMeta("env"))
assert.Equal("", span.GetMeta("component"))
span.Finish()
assert.Equal(map[string]string{"env": "staging"}, tracer.getAllMeta(), "there should be one meta")
tracer.SetMeta("component", "core")
span = tracer.NewRootSpan("pylons.request", "pylons", "/")
assert.Equal("staging", span.GetMeta("env"))
assert.Equal("core", span.GetMeta("component"))
span.Finish()
assert.Equal(map[string]string{"env": "staging", "component": "core"}, tracer.getAllMeta(), "there should be two entries")
tracer.SetMeta("env", "prod")
span = tracer.NewRootSpan("pylons.request", "pylons", "/")
assert.Equal("prod", span.GetMeta("env"))
assert.Equal("core", span.GetMeta("component"))
span.SetMeta("env", "sandbox")
assert.Equal("sandbox", span.GetMeta("env"))
assert.Equal("core", span.GetMeta("component"))
span.Finish()
assert.Equal(map[string]string{"env": "prod", "component": "core"}, tracer.getAllMeta(), "key1 should have been updated")
}
func TestTracerRace(t *testing.T) {
assert := assert.New(t)
tracer, transport := getTestTracer()
defer tracer.Stop()
total := (traceChanLen / 3) / 10
var wg sync.WaitGroup
wg.Add(total)
// Trying to be quite brutal here, firing lots of concurrent things, finishing in
// different orders, and modifying spans after creation.
for n := 0; n < total; n++ {
i := n // keep local copy
odd := ((i % 2) != 0)
go func() {
if i%11 == 0 {
time.Sleep(time.Microsecond)
}
tracer.SetMeta("foo", "bar")
parent := tracer.NewRootSpan("pylons.request", "pylons", "/")
NewChildSpan("redis.command", parent).Finish()
child := NewChildSpan("async.service", parent)
if i%13 == 0 {
time.Sleep(time.Microsecond)
}
if odd {
parent.SetMeta("odd", "true")
parent.SetMetric("oddity", 1)
parent.Finish()
} else {
child.SetMeta("odd", "false")
child.SetMetric("oddity", 0)
child.Finish()
}
if i%17 == 0 {
time.Sleep(time.Microsecond)
}
if odd {
child.Resource = "HGETALL"
child.SetMeta("odd", "false")
child.SetMetric("oddity", 0)
} else {
parent.Resource = "/" + strconv.Itoa(i) + ".html"
parent.SetMeta("odd", "true")
parent.SetMetric("oddity", 1)
}
if i%19 == 0 {
time.Sleep(time.Microsecond)
}
if odd {
child.Finish()
} else {
parent.Finish()
}
wg.Done()
}()
}
wg.Wait()
tracer.ForceFlush()
traces := transport.Traces()
assert.Len(traces, total, "we should have exactly as many traces as expected")
for _, trace := range traces {
assert.Len(trace, 3, "each trace should have exactly 3 spans")
var parent, child, redis *Span
for _, span := range trace {
assert.Equal("bar", span.GetMeta("foo"), "tracer meta should have been applied to all spans")
switch span.Name {
case "pylons.request":
parent = span
case "async.service":
child = span
case "redis.command":
redis = span
default:
assert.Fail("unexpected span", span)
}
}
assert.NotNil(parent)
assert.NotNil(child)
assert.NotNil(redis)
assert.Equal(uint64(0), parent.ParentID)
assert.Equal(parent.TraceID, parent.SpanID)
assert.Equal(parent.TraceID, redis.TraceID)
assert.Equal(parent.TraceID, child.TraceID)
assert.Equal(parent.TraceID, redis.ParentID)
assert.Equal(parent.TraceID, child.ParentID)
}
}
// TestWorker is definitely a flaky test, as here we test that the worker
// background task actually does flush things. Most other tests are and should
// be using ForceFlush() to make sure things are really sent to transport.
// Here, we just wait until things show up, as we would do with a real program.
func TestWorker(t *testing.T) {
assert := assert.New(t)
tracer, transport := getTestTracer()
defer tracer.Stop()
n := traceChanLen * 10 // put more traces than the chan size, on purpose
for i := 0; i < n; i++ {
root := tracer.NewRootSpan("pylons.request", "pylons", "/")
child := tracer.NewChildSpan("redis.command", root)
child.Finish()
root.Finish()
}
now := time.Now()
count := 0
for time.Now().Before(now.Add(time.Minute)) && count < traceChanLen {
nbTraces := len(transport.Traces())
if nbTraces > 0 {
t.Logf("popped %d traces", nbTraces)
}
count += nbTraces
time.Sleep(time.Millisecond)
}
// here we just check that we have "enough traces". In practice, lots of them
// are dropped, it's another interesting side-effect of this test: it does
// trigger error messages (which are repeated, so it aggregates them etc.)
if count < traceChanLen {
assert.Fail(fmt.Sprintf("timeout, not enough traces in buffer (%d/%d)", count, n))
}
}
// BenchmarkConcurrentTracing tests the performance of spawning a lot of
// goroutines where each one creates a trace with a parent and a child.
func BenchmarkConcurrentTracing(b *testing.B) {
tracer, _ := getTestTracer()
defer tracer.Stop()
b.ResetTimer()
for n := 0; n < b.N; n++ {
go func() {
parent := tracer.NewRootSpan("pylons.request", "pylons", "/")
defer parent.Finish()
for i := 0; i < 10; i++ {
tracer.NewChildSpan("redis.command", parent).Finish()
}
}()
}
}
// BenchmarkTracerAddSpans tests the performance of creating and finishing a root
// span. It should include the encoding overhead.
func BenchmarkTracerAddSpans(b *testing.B) {
tracer, _ := getTestTracer()
defer tracer.Stop()
for n := 0; n < b.N; n++ {
span := tracer.NewRootSpan("pylons.request", "pylons", "/")
span.Finish()
}
}
// getTestTracer returns a Tracer with a DummyTransport
func getTestTracer() (*Tracer, *dummyTransport) {
transport := &dummyTransport{getEncoder: msgpackEncoderFactory}
tracer := NewTracerTransport(transport)
return tracer, transport
}
// Mock Transport with a real Encoder
type dummyTransport struct {
getEncoder encoderFactory
traces [][]*Span
services map[string]Service
sync.RWMutex // required because of some poll-testing (eg: worker)
}
func (t *dummyTransport) SendTraces(traces [][]*Span) (*http.Response, error) {
t.Lock()
t.traces = append(t.traces, traces...)
t.Unlock()
encoder := t.getEncoder()
return nil, encoder.EncodeTraces(traces)
}
func (t *dummyTransport) SendServices(services map[string]Service) (*http.Response, error) {
t.Lock()
t.services = services
t.Unlock()
encoder := t.getEncoder()
return nil, encoder.EncodeServices(services)
}
func (t *dummyTransport) Traces() [][]*Span {
t.Lock()
defer t.Unlock()
traces := t.traces
t.traces = nil
return traces
}
func (t *dummyTransport) SetHeader(key, value string) {}

View file

@ -1,202 +0,0 @@
package tracer
import (
"net/http"
"net/http/httptest"
"net/url"
"strconv"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
// getTestSpan returns a Span with different fields set
func getTestSpan() *Span {
return &Span{
TraceID: 42,
SpanID: 52,
ParentID: 42,
Type: "web",
Service: "high.throughput",
Name: "sending.events",
Resource: "SEND /data",
Start: 1481215590883401105,
Duration: 1000000000,
Meta: map[string]string{"http.host": "192.168.0.1"},
Metrics: map[string]float64{"http.monitor": 41.99},
}
}
// getTestTrace returns a list of traces that is composed by ``traceN`` number
// of traces, each one composed by ``size`` number of spans.
func getTestTrace(traceN, size int) [][]*Span {
var traces [][]*Span
for i := 0; i < traceN; i++ {
trace := []*Span{}
for j := 0; j < size; j++ {
trace = append(trace, getTestSpan())
}
traces = append(traces, trace)
}
return traces
}
func getTestServices() map[string]Service {
return map[string]Service{
"svc1": Service{Name: "scv1", App: "a", AppType: "b"},
"svc2": Service{Name: "scv2", App: "c", AppType: "d"},
}
}
type mockDatadogAPIHandler struct {
t *testing.T
}
func (m mockDatadogAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
assert := assert.New(m.t)
header := r.Header.Get("X-Datadog-Trace-Count")
assert.NotEqual("", header, "X-Datadog-Trace-Count header should be here")
count, err := strconv.Atoi(header)
assert.Nil(err, "header should be an int")
assert.NotEqual(0, count, "there should be a non-zero amount of traces")
}
func mockDatadogAPINewServer(t *testing.T) *httptest.Server {
handler := mockDatadogAPIHandler{t: t}
server := httptest.NewServer(handler)
return server
}
func TestTracesAgentIntegration(t *testing.T) {
assert := assert.New(t)
testCases := []struct {
payload [][]*Span
}{
{getTestTrace(1, 1)},
{getTestTrace(10, 1)},
{getTestTrace(1, 10)},
{getTestTrace(10, 10)},
}
for _, tc := range testCases {
transport := newHTTPTransport(defaultHostname, defaultPort)
response, err := transport.SendTraces(tc.payload)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
}
func TestAPIDowngrade(t *testing.T) {
assert := assert.New(t)
transport := newHTTPTransport(defaultHostname, defaultPort)
transport.traceURL = "http://localhost:8126/v0.0/traces"
// if we get a 404 we should downgrade the API
traces := getTestTrace(2, 2)
response, err := transport.SendTraces(traces)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
func TestEncoderDowngrade(t *testing.T) {
assert := assert.New(t)
transport := newHTTPTransport(defaultHostname, defaultPort)
transport.traceURL = "http://localhost:8126/v0.2/traces"
// if we get a 415 because of a wrong encoder, we should downgrade the encoder
traces := getTestTrace(2, 2)
response, err := transport.SendTraces(traces)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
func TestTransportServices(t *testing.T) {
assert := assert.New(t)
transport := newHTTPTransport(defaultHostname, defaultPort)
response, err := transport.SendServices(getTestServices())
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
func TestTransportServicesDowngrade_0_0(t *testing.T) {
assert := assert.New(t)
transport := newHTTPTransport(defaultHostname, defaultPort)
transport.serviceURL = "http://localhost:8126/v0.0/services"
response, err := transport.SendServices(getTestServices())
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
func TestTransportServicesDowngrade_0_2(t *testing.T) {
assert := assert.New(t)
transport := newHTTPTransport(defaultHostname, defaultPort)
transport.serviceURL = "http://localhost:8126/v0.2/services"
response, err := transport.SendServices(getTestServices())
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
func TestTransportEncoderPool(t *testing.T) {
assert := assert.New(t)
transport := newHTTPTransport(defaultHostname, defaultPort)
// MsgpackEncoder is the default encoder of the pool
encoder := transport.getEncoder()
assert.Equal("application/msgpack", encoder.ContentType())
}
func TestTransportSwitchEncoder(t *testing.T) {
assert := assert.New(t)
transport := newHTTPTransport(defaultHostname, defaultPort)
transport.changeEncoder(jsonEncoderFactory)
// MsgpackEncoder is the default encoder of the pool
encoder := transport.getEncoder()
assert.Equal("application/json", encoder.ContentType())
}
func TestTraceCountHeader(t *testing.T) {
assert := assert.New(t)
testCases := []struct {
payload [][]*Span
}{
{getTestTrace(1, 1)},
{getTestTrace(10, 1)},
{getTestTrace(100, 10)},
}
receiver := mockDatadogAPINewServer(t)
parsedURL, err := url.Parse(receiver.URL)
assert.NoError(err)
host := parsedURL.Host
hostItems := strings.Split(host, ":")
assert.Equal(2, len(hostItems), "port should be given, as it's chosen randomly")
hostname := hostItems[0]
port := hostItems[1]
for _, tc := range testCases {
transport := newHTTPTransport(hostname, port)
response, err := transport.SendTraces(tc.payload)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
receiver.Close()
}