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