gitlab.com/gitlab-org/labkit@v1.21.0/correlation/generator.go (about) 1 package correlation 2 3 import ( 4 "crypto/rand" 5 "io" 6 "sync" 7 "time" 8 9 "github.com/oklog/ulid/v2" 10 ) 11 12 // Replaceable for testing purposes. 13 var ulidEntropySource io.Reader = &safeMonotonicReader{ 14 delegate: ulid.Monotonic(rand.Reader, 0), 15 } 16 17 func generatePseudorandomCorrelationID() string { 18 return "E:" + encodeReverseBase62(time.Now().UnixNano()) 19 } 20 21 // generateRandomCorrelationID will attempt to generate a correlationid randomly 22 // if this fails, will log a message and fallback to a pseudorandom approach. 23 func generateRandomCorrelationIDWithFallback() string { 24 uid, err := ulid.New(ulid.Timestamp(time.Now()), ulidEntropySource) 25 if err != nil { 26 // Swallow the error and return a pseudorandom correlation_id. 27 // Operators can determine that an error occurred by the shape of the 28 // correlation_id, which will be prefixed with a `E:` 29 return generatePseudorandomCorrelationID() 30 } 31 32 return uid.String() 33 } 34 35 // RandomID generates a random correlation ID. 36 // Deprecated: use SafeRandomID instead. 37 // Note, that this method will not return an error, it is here for compatibility reasons only. 38 func RandomID() (string, error) { return generateRandomCorrelationIDWithFallback(), nil } 39 40 // SafeRandomID generates a random correlation ID. 41 func SafeRandomID() string { return generateRandomCorrelationIDWithFallback() } 42 43 // safeMonotonicReader is a thread-safe wrapper around a ulid.Monotonic instance, which is not safe for concurrent use by itself. 44 // See https://godoc.org/github.com/oklog/ulid#Monotonic. 45 type safeMonotonicReader struct { 46 mtx sync.Mutex 47 delegate ulid.MonotonicReader 48 } 49 50 var _ ulid.MonotonicReader = &safeMonotonicReader{} 51 52 func (r *safeMonotonicReader) MonotonicRead(ms uint64, p []byte) error { 53 r.mtx.Lock() 54 defer r.mtx.Unlock() 55 return r.delegate.MonotonicRead(ms, p) 56 } 57 58 func (r *safeMonotonicReader) Read(p []byte) (int, error) { 59 r.mtx.Lock() 60 defer r.mtx.Unlock() 61 return r.delegate.Read(p) 62 }