Skip to content

Commit

Permalink
Merge pull request #48 from DataDog/nicolas/random
Browse files Browse the repository at this point in the history
use a seeded/thread-safe random number generator for span ids
  • Loading branch information
galdor authored Apr 10, 2017
2 parents 3a07d13 + 0c5fb73 commit ed66a44
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 16 deletions.
47 changes: 47 additions & 0 deletions tracer/rand.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package tracer

import (
cryptorand "crypto/rand"
"log"
"math"
"math/big"
"math/rand"
"sync"
"time"
)

type randSource struct {
source rand.Source
sync.Mutex
}

func newRandSource() (*randSource, error) {
var seed int64

max := big.NewInt(math.MaxInt64)
n, err := cryptorand.Int(cryptorand.Reader, max)
if err == nil {
seed = n.Int64()
} else {
log.Printf("cannot generate random seed: %v; using current time\n", err)
seed = time.Now().UnixNano()
}

source := rand.NewSource(seed)

return &randSource{source: source}, nil
}

func (rs *randSource) Int63() int64 {
rs.Lock()
n := rs.source.Int63()
rs.Unlock()

return n
}

func (rs *randSource) Seed(seed int64) {
rs.Lock()
rs.Seed(seed)
rs.Unlock()
}
6 changes: 0 additions & 6 deletions tracer/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package tracer
import (
"context"
"fmt"
"math/rand"
"reflect"
"runtime/debug"
"strings"
Expand Down Expand Up @@ -221,11 +220,6 @@ func (s *Span) Tracer() *Tracer {
return s.tracer
}

// nextSpanID returns a new random span id.
func nextSpanID() uint64 {
return uint64(rand.Int63())
}

// now returns current UTC time in nanos.
func now() int64 {
return time.Now().UTC().UnixNano()
Expand Down
24 changes: 20 additions & 4 deletions tracer/tracer.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package tracer

import (
"context"
"fmt"
"log"
"math/rand"
"sync"
"time"

"context"
)

const (
Expand Down Expand Up @@ -42,6 +43,8 @@ type Tracer struct {

exit chan struct{}
exitWG *sync.WaitGroup

randGen *rand.Rand
}

// NewTracer creates a new Tracer. Most users should use the package's
Expand All @@ -52,6 +55,12 @@ func NewTracer() *Tracer {

// NewTracerTransport create a new Tracer with the given transport.
func NewTracerTransport(transport Transport) *Tracer {
randSource, err := newRandSource()
if err != nil {
panic(fmt.Sprintf("cannot create random source: %v", err))
}
randGen := rand.New(randSource)

t := &Tracer{
enabled: true,
transport: transport,
Expand All @@ -64,6 +73,8 @@ func NewTracerTransport(transport Transport) *Tracer {

exit: make(chan struct{}),
exitWG: &sync.WaitGroup{},

randGen: randGen,
}

// start a background worker
Expand Down Expand Up @@ -132,7 +143,7 @@ func (t *Tracer) SetServiceInfo(name, app, appType string) {
// NewRootSpan creates a span with no parent. Its ids will be randomly
// assigned.
func (t *Tracer) NewRootSpan(name, service, resource string) *Span {
spanID := nextSpanID()
spanID := t.nextSpanID()
span := NewSpan(name, service, resource, spanID, spanID, 0, t)
t.sampler.Sample(span)
return span
Expand All @@ -141,7 +152,7 @@ func (t *Tracer) NewRootSpan(name, service, resource string) *Span {
// NewChildSpan returns a new span that is child of the Span passed as
// argument.
func (t *Tracer) NewChildSpan(name string, parent *Span) *Span {
spanID := nextSpanID()
spanID := t.nextSpanID()

// when we're using parenting in inner functions, it's possible that
// a nil pointer is sent to this function as argument. To prevent a crash,
Expand Down Expand Up @@ -212,6 +223,11 @@ func (t *Tracer) FlushTraces() error {
return err
}

// nextSpanID returns a new random span id.
func (t *Tracer) nextSpanID() uint64 {
return uint64(t.randGen.Int63())
}

func (t *Tracer) flushServices() error {
if !t.Enabled() || !t.servicesModified {
return nil
Expand Down
12 changes: 6 additions & 6 deletions tracer/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestTracesAgentIntegration(t *testing.T) {
for _, tc := range testCases {
transport := newHTTPTransport(defaultHostname, defaultPort)
response, err := transport.SendTraces(tc.payload)
assert.Nil(err)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
Expand All @@ -74,7 +74,7 @@ func TestAPIDowngrade(t *testing.T) {
// if we get a 404 we should downgrade the API
traces := getTestTrace(2, 2)
response, err := transport.SendTraces(traces)
assert.Nil(err)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
Expand All @@ -87,7 +87,7 @@ func TestEncoderDowngrade(t *testing.T) {
// 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.Nil(err)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
Expand All @@ -98,7 +98,7 @@ func TestTransportServices(t *testing.T) {
transport := newHTTPTransport(defaultHostname, defaultPort)

response, err := transport.SendServices(getTestServices())
assert.Nil(err)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
Expand All @@ -110,7 +110,7 @@ func TestTransportServicesDowngrade_0_0(t *testing.T) {
transport.serviceURL = "http://localhost:8126/v0.0/services"

response, err := transport.SendServices(getTestServices())
assert.Nil(err)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
Expand All @@ -122,7 +122,7 @@ func TestTransportServicesDowngrade_0_2(t *testing.T) {
transport.serviceURL = "http://localhost:8126/v0.2/services"

response, err := transport.SendServices(getTestServices())
assert.Nil(err)
assert.NoError(err)
assert.NotNil(response)
assert.Equal(200, response.StatusCode)
}
Expand Down

0 comments on commit ed66a44

Please sign in to comment.