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  }