mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2024-12-28 21:09:17 +02:00
Guard rng in exemplar rand computation (#5456)
Fix #5455 The `math/rand.Rand` type is not safe for concurrent access. Concurrent measurements, and therefore concurrent exemplar computation, are allowed. Ensure this concurrent design does not lead to data races with `rng`.
This commit is contained in:
parent
d5a66e0e49
commit
047df28b88
@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
- Identify the `Meter` returned from the global `MeterProvider` in `go.opentelemetry.io/otel/global` with its schema URL. (#5426)
|
||||
- Log a warning to the OpenTelemetry internal logger when a `Span` in `go.opentelemetry.io/otel/sdk/trace` drops an attribute, event, or link due to a limit being reached. (#5434)
|
||||
- Document instrument name requirements in `go.opentelemetry.io/otel/metric`. (#5435)
|
||||
- Prevent random number generation data-race for experimental rand exemplars in `go.opentelemetry.io/otel/sdk/metric`. (#5456)
|
||||
|
||||
## [1.27.0/0.49.0/0.3.0] 2024-05-21
|
||||
|
||||
|
@ -7,16 +7,21 @@ import (
|
||||
"context"
|
||||
"math"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
// rng is used to make sampling decisions.
|
||||
//
|
||||
// Do not use crypto/rand. There is no reason for the decrease in performance
|
||||
// given this is not a security sensitive decision.
|
||||
var rng = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
var (
|
||||
// rng is used to make sampling decisions.
|
||||
//
|
||||
// Do not use crypto/rand. There is no reason for the decrease in performance
|
||||
// given this is not a security sensitive decision.
|
||||
rng = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
// Ensure concurrent safe accecess to rng and its underlying source.
|
||||
rngMu sync.Mutex
|
||||
)
|
||||
|
||||
// random returns, as a float64, a uniform pseudo-random number in the open
|
||||
// interval (0.0,1.0).
|
||||
@ -38,6 +43,9 @@ func random() float64 {
|
||||
//
|
||||
// There are likely many other methods to explore here as well.
|
||||
|
||||
rngMu.Lock()
|
||||
defer rngMu.Unlock()
|
||||
|
||||
f := rng.Float64()
|
||||
for f == 0 {
|
||||
f = rng.Float64()
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"math"
|
||||
"slices"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -49,3 +50,18 @@ func TestFixedSizeSamplingCorrectness(t *testing.T) {
|
||||
// ensuring no bias in our random sampling algorithm.
|
||||
assert.InDelta(t, 1/mean, intensity, 0.02) // Within 5σ.
|
||||
}
|
||||
|
||||
func TestRandomConcurrentSafe(t *testing.T) {
|
||||
const goRoutines = 10
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for n := 0; n < goRoutines; n++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_ = random()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user