diff --git a/profiler/options.go b/profiler/options.go index 5d0e94f14d..45257e57b7 100644 --- a/profiler/options.go +++ b/profiler/options.go @@ -9,6 +9,7 @@ import ( "context" "encoding/json" "fmt" + "math/rand" "net" "net/http" "net/url" @@ -111,6 +112,7 @@ type config struct { logStartup bool traceConfig executionTraceConfig endpointCountEnabled bool + rng *rand.Rand } // logStartup records the configuration to the configured logger in JSON format @@ -574,3 +576,10 @@ func WithCustomProfilerLabelKeys(keys ...string) Option { cfg.customProfilerLabels = append(cfg.customProfilerLabels, keys...) } } + +// withRNG provides a seeded RNG, for reliable testing +func withRNG(r *rand.Rand) Option { + return func(cfg *config) { + cfg.rng = r + } +} diff --git a/profiler/profiler.go b/profiler/profiler.go index 5e1d1736e8..852f6811ba 100644 --- a/profiler/profiler.go +++ b/profiler/profiler.go @@ -126,6 +126,13 @@ func (p *profiler) lookupProfile(name string, w io.Writer, debug int) error { return prof.WriteTo(w, debug) } +func (p *profiler) randFloat64() float64 { + if p.cfg.rng != nil { + return p.cfg.rng.Float64() + } + return rand.Float64() +} + // newProfiler creates a new, unstarted profiler. func newProfiler(opts ...Option) (*profiler, error) { if os.Getenv("AWS_LAMBDA_FUNCTION_NAME") != "" { @@ -319,7 +326,7 @@ func (p *profiler) collect(ticker <-chan time.Time) { // we will always record a trace // We do multiplication here instead of division to defensively guard against // division by 0 - shouldTraceRandomly := rand.Float64()*float64(p.cfg.traceConfig.Period) < float64(p.cfg.period) + shouldTraceRandomly := p.randFloat64()*float64(p.cfg.traceConfig.Period) < float64(p.cfg.period) // As a special case, we want to trace during the first // profiling cycle since startup activity is generally much // different than regular operation diff --git a/profiler/profiler_test.go b/profiler/profiler_test.go index 9f5db9e529..5cfbf806e5 100644 --- a/profiler/profiler_test.go +++ b/profiler/profiler_test.go @@ -531,14 +531,13 @@ func TestExecutionTraceMisconfiguration(t *testing.T) { } func TestExecutionTraceRandom(t *testing.T) { - t.Skip("flaky test, see: https://github.com/DataDog/dd-trace-go/issues/2529") - collectTraces := func(t *testing.T, profilePeriod, tracePeriod time.Duration, count int) int { t.Setenv("DD_PROFILING_EXECUTION_TRACE_ENABLED", "true") t.Setenv("DD_PROFILING_EXECUTION_TRACE_PERIOD", tracePeriod.String()) profiles := startTestProfiler(t, 10, WithProfileTypes(), WithPeriod(profilePeriod), + withRNG(rand.New(rand.NewSource(0))), ) seenTraces := 0