github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/infra/logid/logid.go (about) 1 // Package logid provides log ID generators to help service observability, 2 // such as logging, tracing, metrics, etc. 3 package logid 4 5 import ( 6 "encoding/base32" 7 "time" 8 9 "github.com/jxskiss/gopkg/v2/perf/fastrand" 10 ) 11 12 var defaultGen Generator = NewV1Gen() 13 14 type Generator interface { 15 16 // Gen generates a new log ID string, it should always return 17 // a valid log ID, and don't generate duplicate log IDs. 18 Gen() string 19 } 20 21 // SetDefault changes the default generator. 22 // 23 // The default generator may be changed by the main program, 24 // but generally library code shall not call this function. 25 func SetDefault(gen Generator) { 26 defaultGen = gen 27 } 28 29 // Gen generates a new log ID string using the default generator. 30 func Gen() string { 31 return defaultGen.Gen() 32 } 33 34 // Crockford's Base32 Encoding 35 // https://www.crockford.com/base32.html 36 var ( 37 b32Chars = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" 38 b32Enc = base32.NewEncoding(b32Chars).WithPadding(base32.NoPadding) 39 b32Dec = "" 40 ) 41 42 func init() { 43 buf := make([]byte, 128) 44 for i := range buf { 45 buf[i] = 0xff 46 } 47 for i, c := range b32Chars { 48 buf[c] = byte(i) 49 if c >= 'A' && c <= 'Z' { 50 buf[c+'a'-'A'] = byte(i) 51 } 52 } 53 b32Dec = string(buf) 54 } 55 56 func encodeBase32(b []byte, x int64) { 57 i := len(b) - 1 58 for i >= 0 { 59 b[i] = b32Chars[x&31] 60 x >>= 5 61 i-- 62 } 63 } 64 65 func decodeBase32(b string) (x int64, err error) { 66 for i, c := range b { 67 if b32Dec[c] == 0xff { 68 return 0, base32.CorruptInputError(i) 69 } 70 x = (x << 5) | int64(b32Dec[c]) 71 } 72 return x, nil 73 } 74 75 const mask50bits = (1 << 50) - 1 76 77 func rand50bits() int64 { 78 x := fastrand.Uint64() & mask50bits 79 return int64(x) 80 } 81 82 // strTimeMilli is the time format used in string form of a log ID info. 83 const strTimeMilli = "20060102.15:04:05.000Z0700" 84 85 func formatTime(t time.Time) string { 86 return t.Format(strTimeMilli) 87 } 88 89 // minLength is the minimum length of a log ID generated by this package. 90 // Update this constant when adding new generators. 91 const minLength = v2IPv4Length 92 93 // Decode decodes a log ID string and returns the parsed information. 94 func Decode(s string) (info Info) { 95 if len(s) >= minLength { 96 switch s[len(s)-1] { 97 case v1Version: 98 return decodeV1Info(s) 99 case v2Version: 100 return decodeV2Info(s) 101 } 102 } 103 return invalidInfo{} 104 } 105 106 // Info holds parsed information of a log ID string. 107 type Info interface { 108 // Valid tells whether it is a valid log ID generated by this package. 109 Valid() bool 110 111 // Version returns the version of the log ID. 112 Version() byte 113 114 // String returns the human-friendly string representation of the log ID, 115 // e.g. 116 // "1|20240125.10:07:20.485+0800|M0RY2MKE72XWXGSW|140NFEAD8J" 117 // "2|20240125.10:07:20.486+0800|fdbd:dc01:16:16::94|CBDDWZEJH4" 118 String() string 119 } 120 121 type invalidInfo struct{} 122 123 func (invalidInfo) Valid() bool { return false } 124 func (invalidInfo) Version() byte { return '0' } 125 func (invalidInfo) String() string { return "0|invalid" }