forked from gookit/slog
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.go
164 lines (136 loc) · 3.63 KB
/
util.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
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
package slog
import (
"fmt"
"os"
"path"
"runtime"
"strconv"
"strings"
"github.com/gookit/goutil/stdutil"
"github.com/gookit/goutil/strutil"
"github.com/valyala/bytebufferpool"
)
const (
defaultMaxCallerDepth int = 15
defaultKnownSlogFrames int = 4
)
// var (
// argFmtPool bytebufferpool.Pool
// )
// Stack that attempts to recover the data for all goroutines.
// func getCallStacks(callerSkip int) []byte {
// return nil
// }
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 < 1 {
return
}
f, _ := runtime.CallersFrames(pcs).Next()
return f, f.PC != 0
}
func formatCaller(rf *runtime.Frame, flag uint8) (cs string) {
switch flag {
case CallerFlagFull:
// eg: "github.com/gookit/slog_test.TestLogger_ReportCaller,logger_test.go:48"
return rf.Function + "," + path.Base(rf.File) + ":" + strconv.FormatInt(int64(rf.Line), 10)
case CallerFlagFunc:
return rf.Function
case CallerFlagPkg:
i := strings.LastIndex(rf.Function, "/")
i += strings.IndexByte(rf.Function[i+1:], '.')
return rf.Function[:i+1]
case CallerFlagFnlFcn:
ss := strings.Split(rf.Function, ".")
return path.Base(rf.File) + ":" + strconv.Itoa(rf.Line) + "," + ss[len(ss)-1]
case CallerFlagFnLine:
return path.Base(rf.File) + ":" + strconv.Itoa(rf.Line)
case CallerFlagFcName:
ss := strings.Split(rf.Function, ".")
return ss[len(ss)-1]
default: // CallerFlagFpLine
return rf.File + ":" + strconv.Itoa(rf.Line)
}
}
// it like Println, will add spaces for each argument
func formatArgsWithSpaces(vs []interface{}) string {
ln := len(vs)
if ln == 0 {
return ""
}
if ln == 1 {
// return strutil.ToBytes(msg) // perf: Reduce one memory allocation
return stdutil.ToString(vs[0]) // perf: Reduce one memory allocation
}
// buf = make([]byte, 0, ln*8)
bb := bytebufferpool.Get()
defer bytebufferpool.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 {
// str, _ := strutil.AnyToString(vs[i], false)
str := stdutil.ToString(vs[i])
if i > 0 { // add space
// buf = append(buf, ' ')
bb.B = append(bb.B, ' ')
}
// buf = append(buf, str...)
bb.B = append(bb.B, str...)
}
return bb.String()
}
// EncodeToString data to string
func EncodeToString(v interface{}) string {
if mp, ok := v.(map[string]interface{}); ok {
return mapToString(mp)
}
return stdutil.ToString(v)
}
func mapToString(mp map[string]interface{}) 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 printlnStderr(args ...interface{}) {
_, _ = fmt.Fprintln(os.Stderr, args...)
}