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  }