-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathutil.go
More file actions
182 lines (156 loc) · 4.23 KB
/
Copy pathutil.go
File metadata and controls
182 lines (156 loc) · 4.23 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package slog
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"github.com/gookit/goutil/byteutil"
"github.com/gookit/goutil/strutil"
"github.com/valyala/bytebufferpool"
)
// const (
// defaultMaxCallerDepth int = 15
// defaultKnownSlogFrames int = 4
// )
// Stack that attempts to recover the data for all goroutines.
// func getCallStacks(callerSkip int) []byte {
// return nil
// }
// FormatLevelName Format the level name, specify the length returned,
// fill the space with less length, and truncate than the length
func FormatLevelName(name string, length int) string {
if len(name) < length {
return fmt.Sprintf("%-"+strconv.Itoa(length)+"s", name)
}
return name[:length]
}
func buildLowerLevelName() map[Level]string {
mp := make(map[Level]string, len(LevelNames))
for level, s := range LevelNames {
mp[level] = strings.ToLower(s)
}
return mp
}
// getCaller retrieves the name of the first non-slog calling function
func getCaller(callerSkip int) (fr runtime.Frame, ok bool) {
pcs := make([]uintptr, 1) // alloc 1 times
num := runtime.Callers(callerSkip, pcs)
if num > 0 {
fr, _ = runtime.CallersFrames(pcs).Next()
ok = fr.PC != 0
}
return
}
func formatCaller(rf *runtime.Frame, flag uint8, userFn CallerFormatFn) (cs string) {
if userFn != nil {
return userFn(rf)
}
lineNum := strconv.FormatInt(int64(rf.Line), 10)
switch flag {
case CallerFlagFull:
return rf.Function + "," + filepath.Base(rf.File) + ":" + lineNum
case CallerFlagFunc:
return rf.Function
case CallerFlagFcLine:
return rf.Function + ":" + lineNum
case CallerFlagPkg:
i := strings.LastIndex(rf.Function, "/")
i += strings.IndexByte(rf.Function[i+1:], '.')
return rf.Function[:i+1]
case CallerFlagPkgFnl:
i := strings.LastIndex(rf.Function, "/")
i += strings.IndexByte(rf.Function[i+1:], '.')
return rf.Function[:i+1] + "," + filepath.Base(rf.File) + ":" + lineNum
case CallerFlagFnlFcn:
ss := strings.Split(rf.Function, ".")
return filepath.Base(rf.File) + ":" + lineNum + "," + ss[len(ss)-1]
case CallerFlagFnLine:
return filepath.Base(rf.File) + ":" + lineNum
case CallerFlagFcName:
ss := strings.Split(rf.Function, ".")
return ss[len(ss)-1]
default: // CallerFlagFpLine
return rf.File + ":" + lineNum
}
}
var msgBufPool bytebufferpool.Pool
// it like Println, will add spaces for each argument
func formatArgsWithSpaces(vs []any) string {
ln := len(vs)
if ln == 0 {
return ""
}
if ln == 1 {
// cast is string, return it. NOT ALLOC MEMORY
if str, ok := vs[0].(string); ok {
return str
}
return strutil.SafeString(vs[0])
}
// buf = make([]byte, 0, ln*8)
bb := msgBufPool.Get()
defer msgBufPool.Put(bb)
// TIP:
// `float` to string - will alloc 2 times memory
// `int <0`, `int > 100` to string - will alloc 1 times memory
for i := range vs {
if i > 0 { // add space
bb.B = append(bb.B, ' ')
}
bb.B = byteutil.AppendAny(bb.B, vs[i])
}
return string(bb.B)
// return byteutil.String(bb.B) // perf: Reduce one memory allocation
}
// EncodeToString data to string
func EncodeToString(v any) string {
switch mp := v.(type) {
case M:
// Record.Data/Extra are the named type M. Handle it directly to skip the
// SafeString -> Stringer-dispatch -> M.String() indirection (same output).
return mapToString(mp)
case map[string]any:
return mapToString(mp)
}
return strutil.SafeString(v)
}
func mapToString(mp map[string]any) string {
ln := len(mp)
if ln == 0 {
return "{}"
}
// TODO use bytebufferpool
buf := make([]byte, 0, ln*8)
buf = append(buf, '{')
for k, val := range mp {
buf = append(buf, k...)
buf = append(buf, ':')
str, _ := strutil.AnyToString(val, false)
buf = append(buf, str...)
buf = append(buf, ',', ' ')
}
// remove last ', '
buf = append(buf[:len(buf)-2], '}')
return strutil.Byte2str(buf)
}
func parseTemplateToFields(tplStr string) []string {
ss := strings.Split(tplStr, "{{")
vars := make([]string, 0, len(ss)*2)
for _, s := range ss {
if len(s) == 0 {
continue
}
fieldAndOther := strings.SplitN(s, "}}", 2)
if len(fieldAndOther) < 2 {
vars = append(vars, s)
} else {
vars = append(vars, fieldAndOther[0], "}}"+fieldAndOther[1])
}
}
return vars
}
func printStderr(args ...any) {
_, _ = fmt.Fprintln(os.Stderr, args...)
}