Skip to content

Commit 13735fa

Browse files
committed
fix NewRandomRatioBased panic
1 parent 7f16014 commit 13735fa

File tree

3 files changed

+39
-49
lines changed

3 files changed

+39
-49
lines changed

pkg/tracing/sampler/sampling.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,37 @@
11
package sampler
22

33
import (
4+
"encoding/binary"
45
"fmt"
6+
"math"
57

68
sdktrace "go.opentelemetry.io/otel/sdk/trace"
79
"go.opentelemetry.io/otel/trace"
810
)
911

10-
type randGenerator interface {
11-
Float64() float64
12-
}
13-
1412
type RandomRatioBased struct {
1513
sdktrace.Sampler
16-
rnd randGenerator
17-
fraction float64
14+
max uint64
1815
}
1916

2017
// NewRandomRatioBased creates a sampler based on random number.
2118
// fraction parameter should be between 0 and 1 where:
2219
// fraction >= 1 it will always sample
2320
// fraction <= 0 it will never sample
24-
func NewRandomRatioBased(fraction float64, rnd randGenerator) sdktrace.Sampler {
21+
func NewRandomRatioBased(fraction float64) sdktrace.Sampler {
2522
if fraction >= 1 {
2623
return sdktrace.AlwaysSample()
2724
} else if fraction <= 0 {
2825
return sdktrace.NeverSample()
2926
}
3027

31-
return &RandomRatioBased{rnd: rnd, fraction: fraction}
28+
return &RandomRatioBased{max: uint64(fraction * math.MaxUint64)}
3229
}
3330

3431
func (s *RandomRatioBased) ShouldSample(p sdktrace.SamplingParameters) sdktrace.SamplingResult {
32+
val := binary.BigEndian.Uint64(p.TraceID[8:16])
3533
psc := trace.SpanContextFromContext(p.ParentContext)
36-
shouldSample := s.rnd.Float64() < s.fraction
34+
shouldSample := val < s.max
3735
if shouldSample {
3836
return sdktrace.SamplingResult{
3937
Decision: sdktrace.RecordAndSample,
@@ -47,5 +45,5 @@ func (s *RandomRatioBased) ShouldSample(p sdktrace.SamplingParameters) sdktrace.
4745
}
4846

4947
func (s *RandomRatioBased) Description() string {
50-
return fmt.Sprintf("RandomRatioBased{%g}", s.fraction)
48+
return fmt.Sprintf("RandomRatioBased{%v}", s.max)
5149
}

pkg/tracing/sampler/sampling_test.go

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,78 +2,72 @@ package sampler
22

33
import (
44
"context"
5-
"math/rand"
65
"testing"
76

87
"github.com/stretchr/testify/require"
8+
"go.opentelemetry.io/contrib/propagators/aws/xray"
99
sdktrace "go.opentelemetry.io/otel/sdk/trace"
1010
"go.opentelemetry.io/otel/trace"
1111
)
1212

13-
type mockGenerator struct {
14-
mockedValue float64
15-
}
16-
17-
func (g *mockGenerator) Float64() float64 {
18-
return g.mockedValue
19-
}
20-
2113
func Test_ShouldSample(t *testing.T) {
22-
traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
2314
parentCtx := trace.ContextWithSpanContext(
2415
context.Background(),
2516
trace.NewSpanContext(trace.SpanContextConfig{
2617
TraceState: trace.TraceState{},
2718
}),
2819
)
2920

21+
generator := xray.NewIDGenerator()
22+
3023
tests := []struct {
31-
name string
32-
samplingDecision sdktrace.SamplingDecision
33-
fraction float64
34-
generator randGenerator
24+
name string
25+
fraction float64
3526
}{
3627
{
37-
name: "should always sample",
38-
samplingDecision: sdktrace.RecordAndSample,
39-
fraction: 1,
40-
generator: rand.New(rand.NewSource(rand.Int63())),
28+
name: "should always sample",
29+
fraction: 1,
4130
},
4231
{
43-
name: "should nerver sample",
44-
samplingDecision: sdktrace.Drop,
45-
fraction: 0,
46-
generator: rand.New(rand.NewSource(rand.Int63())),
32+
name: "should nerver sample",
33+
fraction: 0,
4734
},
4835
{
49-
name: "should sample when fraction is above generated",
50-
samplingDecision: sdktrace.RecordAndSample,
51-
fraction: 0.5,
52-
generator: &mockGenerator{0.2},
36+
name: "should sample 50%",
37+
fraction: 0.5,
5338
},
5439
{
55-
name: "should not sample when fraction is not above generated",
56-
samplingDecision: sdktrace.Drop,
57-
fraction: 0.5,
58-
generator: &mockGenerator{0.8},
40+
name: "should sample 10%",
41+
fraction: 0.1,
42+
},
43+
{
44+
name: "should sample 1%",
45+
fraction: 0.01,
5946
},
6047
}
6148

49+
totalIterations := 10000
6250
for _, tt := range tests {
6351
t.Run(tt.name, func(t *testing.T) {
64-
s := NewRandomRatioBased(tt.fraction, tt.generator)
65-
for i := 0; i < 100; i++ {
66-
52+
totalSampled := 0
53+
s := NewRandomRatioBased(tt.fraction)
54+
for i := 0; i < totalIterations; i++ {
55+
traceId, _ := generator.NewIDs(context.Background())
6756
r := s.ShouldSample(
6857
sdktrace.SamplingParameters{
6958
ParentContext: parentCtx,
70-
TraceID: traceID,
59+
TraceID: traceId,
7160
Name: "test",
7261
Kind: trace.SpanKindServer,
7362
})
74-
75-
require.Equal(t, tt.samplingDecision, r.Decision)
63+
if r.Decision == sdktrace.RecordAndSample {
64+
totalSampled += 1
65+
}
7666
}
67+
68+
tolerance := 0.1
69+
expected := tt.fraction * float64(totalIterations)
70+
require.InDelta(t, expected, totalSampled, expected*tolerance)
7771
})
7872
}
7973
}

pkg/tracing/tracing.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import (
44
"context"
55
"flag"
66
"fmt"
7-
"math/rand"
87
"strings"
9-
"time"
108

119
"github.com/go-kit/log/level"
1210
"github.com/pkg/errors"
@@ -134,7 +132,7 @@ func newTraceProvider(r *resource.Resource, c Config, exporter *otlptrace.Export
134132
switch strings.ToLower(c.Otel.ExporterType) {
135133
case "awsxray":
136134
options = append(options, sdktrace.WithIDGenerator(xray.NewIDGenerator()))
137-
options = append(options, sdktrace.WithSampler(sdktrace.ParentBased(sampler.NewRandomRatioBased(c.Otel.SampleRatio, rand.New(rand.NewSource(time.Now().Unix()))))))
135+
options = append(options, sdktrace.WithSampler(sdktrace.ParentBased(sampler.NewRandomRatioBased(c.Otel.SampleRatio))))
138136
default:
139137
options = append(options, sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(c.Otel.SampleRatio))))
140138
}

0 commit comments

Comments
 (0)