go.undefinedlabs.com/scopeagent@v0.4.2/tracer/util.go (about) 1 package tracer 2 3 import ( 4 cryptorand "crypto/rand" 5 "encoding/hex" 6 "math" 7 "math/big" 8 "math/rand" 9 "sync" 10 "time" 11 12 "github.com/google/uuid" 13 "go.undefinedlabs.com/scopeagent/instrumentation" 14 ) 15 16 var ( 17 random *rand.Rand 18 mu sync.Mutex 19 ) 20 21 func getRandomId() uint64 { 22 mu.Lock() 23 defer mu.Unlock() 24 ensureRandom() 25 return random.Uint64() 26 } 27 28 func ensureRandom() { 29 if random == nil { 30 random = rand.New(&safeSource{ 31 source: rand.NewSource(getSeed()), 32 }) 33 } 34 } 35 36 //go:noinline 37 func getSeed() int64 { 38 var seed int64 39 n, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)) 40 if err == nil { 41 seed = n.Int64() 42 } else { 43 instrumentation.Logger().Printf("cryptorand error generating seed: %v. \n falling back to time.Now()", err) 44 45 // Adding some jitter to the clock seed using golang channels and goroutines 46 jitterStart := time.Now() 47 cb := make(chan time.Time, 0) 48 go func() { cb <- <-time.After(time.Nanosecond) }() 49 now := <-cb 50 jitter := time.Since(jitterStart) 51 52 // Seed based on the clock + some jitter 53 seed = now.Add(jitter).UnixNano() 54 } 55 instrumentation.Logger().Printf("seed: %d", seed) 56 return seed 57 } 58 59 // safeSource holds a thread-safe implementation of rand.Source64. 60 type safeSource struct { 61 source rand.Source 62 sync.Mutex 63 } 64 65 func (rs *safeSource) Int63() int64 { 66 rs.Lock() 67 n := rs.source.Int63() 68 rs.Unlock() 69 70 return n 71 } 72 73 func (rs *safeSource) Uint64() uint64 { return uint64(rs.Int63()) } 74 75 func (rs *safeSource) Seed(seed int64) { 76 rs.Lock() 77 rs.source.Seed(seed) 78 rs.Unlock() 79 } 80 81 func UUIDToString(uuid uuid.UUID) string { 82 return hex.EncodeToString(uuid[:]) 83 } 84 85 func StringToUUID(val string) (uuid.UUID, error) { 86 if data, err := hex.DecodeString(val); err != nil { 87 return uuid.UUID{}, err 88 } else { 89 return uuid.FromBytes(data) 90 } 91 }