@@ -19,15 +19,8 @@ limitations under the License.
19
19
package glogr
20
20
21
21
import (
22
- "bytes"
23
- "fmt"
24
- "path/filepath"
25
- "reflect"
26
- "runtime"
27
- "strconv"
28
- "strings"
29
-
30
22
"github.com/go-logr/logr"
23
+ "github.com/go-logr/logr/funcr"
31
24
"github.com/golang/glog"
32
25
)
33
26
@@ -42,12 +35,17 @@ func NewWithOptions(opts Options) logr.Logger {
42
35
opts .Depth = 0
43
36
}
44
37
38
+ fopts := funcr.Options {
39
+ LogCaller : funcr .MessageClass (opts .LogCaller ),
40
+ }
41
+
45
42
gl := & glogger {
46
- prefix : "" ,
47
- values : nil ,
48
- depth : opts .Depth ,
49
- logCaller : opts .LogCaller ,
43
+ Formatter : funcr .NewFormatter (fopts ),
50
44
}
45
+
46
+ // For skipping glogger.Info and glogger.Error.
47
+ gl .Formatter .AddCallDepth (opts .Depth )
48
+
51
49
return logr .New (gl )
52
50
}
53
51
@@ -82,246 +80,43 @@ const (
82
80
)
83
81
84
82
type glogger struct {
85
- prefix string
86
- values []interface {}
87
- depth int
88
- logCaller MessageClass
83
+ funcr.Formatter
89
84
}
90
85
91
86
var _ logr.LogSink = & glogger {}
92
87
var _ logr.CallDepthLogSink = & glogger {}
93
88
94
- func flatten (kvList ... interface {}) string {
95
- if len (kvList )% 2 != 0 {
96
- kvList = append (kvList , "<no-value>" )
97
- }
98
- // Empirically bytes.Buffer is faster than strings.Builder for this.
99
- buf := bytes .NewBuffer (make ([]byte , 0 , 1024 ))
100
- for i := 0 ; i < len (kvList ); i += 2 {
101
- k , ok := kvList [i ].(string )
102
- if ! ok {
103
- k = fmt .Sprintf ("<non-string-key-%d>" , i / 2 )
104
- }
105
- v := kvList [i + 1 ]
106
-
107
- if i > 0 {
108
- buf .WriteRune (' ' )
109
- }
110
- buf .WriteRune ('"' )
111
- buf .WriteString (k )
112
- buf .WriteRune ('"' )
113
- buf .WriteRune ('=' )
114
- buf .WriteString (pretty (v ))
115
- }
116
- return buf .String ()
117
- }
118
-
119
- func pretty (value interface {}) string {
120
- return prettyWithFlags (value , 0 )
121
- }
122
-
123
- const (
124
- flagRawString = 0x1
125
- )
126
-
127
- // TODO: This is not fast. Most of the overhead goes here.
128
- func prettyWithFlags (value interface {}, flags uint32 ) string {
129
- // Handling the most common types without reflect is a small perf win.
130
- switch v := value .(type ) {
131
- case bool :
132
- return strconv .FormatBool (v )
133
- case string :
134
- if flags & flagRawString > 0 {
135
- return v
136
- }
137
- // This is empirically faster than strings.Builder.
138
- return `"` + v + `"`
139
- case int :
140
- return strconv .FormatInt (int64 (v ), 10 )
141
- case int8 :
142
- return strconv .FormatInt (int64 (v ), 10 )
143
- case int16 :
144
- return strconv .FormatInt (int64 (v ), 10 )
145
- case int32 :
146
- return strconv .FormatInt (int64 (v ), 10 )
147
- case int64 :
148
- return strconv .FormatInt (int64 (v ), 10 )
149
- case uint :
150
- return strconv .FormatUint (uint64 (v ), 10 )
151
- case uint8 :
152
- return strconv .FormatUint (uint64 (v ), 10 )
153
- case uint16 :
154
- return strconv .FormatUint (uint64 (v ), 10 )
155
- case uint32 :
156
- return strconv .FormatUint (uint64 (v ), 10 )
157
- case uint64 :
158
- return strconv .FormatUint (v , 10 )
159
- case uintptr :
160
- return strconv .FormatUint (uint64 (v ), 10 )
161
- case float32 :
162
- return strconv .FormatFloat (float64 (v ), 'f' , - 1 , 32 )
163
- case float64 :
164
- return strconv .FormatFloat (v , 'f' , - 1 , 64 )
165
- }
166
-
167
- buf := bytes .NewBuffer (make ([]byte , 0 , 256 ))
168
- t := reflect .TypeOf (value )
169
- if t == nil {
170
- return "null"
171
- }
172
- v := reflect .ValueOf (value )
173
- switch t .Kind () {
174
- case reflect .Bool :
175
- return strconv .FormatBool (v .Bool ())
176
- case reflect .String :
177
- if flags & flagRawString > 0 {
178
- return v .String ()
179
- }
180
- // This is empirically faster than strings.Builder.
181
- return `"` + v .String () + `"`
182
- case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
183
- return strconv .FormatInt (int64 (v .Int ()), 10 )
184
- case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
185
- return strconv .FormatUint (uint64 (v .Uint ()), 10 )
186
- case reflect .Float32 :
187
- return strconv .FormatFloat (float64 (v .Float ()), 'f' , - 1 , 32 )
188
- case reflect .Float64 :
189
- return strconv .FormatFloat (v .Float (), 'f' , - 1 , 64 )
190
- case reflect .Struct :
191
- buf .WriteRune ('{' )
192
- for i := 0 ; i < t .NumField (); i ++ {
193
- f := t .Field (i )
194
- if f .PkgPath != "" {
195
- // reflect says this field is only defined for non-exported fields.
196
- continue
197
- }
198
- if i > 0 {
199
- buf .WriteRune (',' )
200
- }
201
- buf .WriteRune ('"' )
202
- name := f .Name
203
- if tag , found := f .Tag .Lookup ("json" ); found {
204
- if comma := strings .Index (tag , "," ); comma != - 1 {
205
- name = tag [:comma ]
206
- } else {
207
- name = tag
208
- }
209
- }
210
- buf .WriteString (name )
211
- buf .WriteRune ('"' )
212
- buf .WriteRune (':' )
213
- buf .WriteString (pretty (v .Field (i ).Interface ()))
214
- }
215
- buf .WriteRune ('}' )
216
- return buf .String ()
217
- case reflect .Slice , reflect .Array :
218
- buf .WriteRune ('[' )
219
- for i := 0 ; i < v .Len (); i ++ {
220
- if i > 0 {
221
- buf .WriteRune (',' )
222
- }
223
- e := v .Index (i )
224
- buf .WriteString (pretty (e .Interface ()))
225
- }
226
- buf .WriteRune (']' )
227
- return buf .String ()
228
- case reflect .Map :
229
- buf .WriteRune ('{' )
230
- // This does not sort the map keys, for best perf.
231
- it := v .MapRange ()
232
- i := 0
233
- for it .Next () {
234
- if i > 0 {
235
- buf .WriteRune (',' )
236
- }
237
- // JSON only does string keys.
238
- buf .WriteRune ('"' )
239
- buf .WriteString (prettyWithFlags (it .Key ().Interface (), flagRawString ))
240
- buf .WriteRune ('"' )
241
- buf .WriteRune (':' )
242
- buf .WriteString (pretty (it .Value ().Interface ()))
243
- i ++
244
- }
245
- buf .WriteRune ('}' )
246
- return buf .String ()
247
- case reflect .Ptr , reflect .Interface :
248
- return pretty (v .Elem ().Interface ())
249
- }
250
- return fmt .Sprintf (`"<unhandled-%s>"` , t .Kind ().String ())
251
- }
252
-
253
- type callerID struct {
254
- File string `json:"file"`
255
- Line int `json:"line"`
256
- }
257
-
258
- func (l glogger ) caller () callerID {
259
- // +1 for this frame, +1 for Info/Error.
260
- _ , file , line , ok := runtime .Caller (l .depth + 2 )
261
- if ! ok {
262
- return callerID {"<unknown>" , 0 }
263
- }
264
- return callerID {filepath .Base (file ), line }
265
- }
266
-
267
- func (l * glogger ) Init (info logr.RuntimeInfo ) {
268
- l .depth += info .CallDepth
269
- }
270
-
271
89
func (l glogger ) Enabled (level int ) bool {
272
90
return bool (glog .V (glog .Level (level )))
273
91
}
274
92
275
93
func (l glogger ) Info (level int , msg string , kvList ... interface {}) {
276
- args := make ([] interface {}, 0 , 64 ) // using a constant here impacts perf
277
- if l . logCaller == All || l . logCaller == Info {
278
- args = append ( args , "caller" , l . caller ())
94
+ prefix , args := l . FormatInfo ( level , msg , kvList )
95
+ if prefix != "" {
96
+ args = prefix + ": " + args
279
97
}
280
- args = append (args , "level" , level , "msg" , msg )
281
- args = append (args , l .values ... )
282
- args = append (args , kvList ... )
283
- argsStr := flatten (args ... )
284
- glog .InfoDepth (l .depth + 1 , l .prefix , argsStr )
98
+ glog .InfoDepth (l .Formatter .GetDepth ()+ 1 , args )
285
99
}
286
100
287
101
func (l glogger ) Error (err error , msg string , kvList ... interface {}) {
288
- args := make ([] interface {}, 0 , 64 ) // using a constant here impacts perf
289
- if l . logCaller == All || l . logCaller == Error {
290
- args = append ( args , "caller" , l . caller ())
102
+ prefix , args := l . FormatError ( err , msg , kvList )
103
+ if prefix != "" {
104
+ args = prefix + ": " + args
291
105
}
292
- args = append (args , "msg" , msg )
293
- var loggableErr interface {}
294
- if err != nil {
295
- loggableErr = err .Error ()
296
- }
297
- args = append (args , "error" , loggableErr )
298
- args = append (args , l .values ... )
299
- args = append (args , kvList ... )
300
- argsStr := flatten (args ... )
301
- glog .ErrorDepth (l .depth + 1 , l .prefix , argsStr )
106
+ glog .ErrorDepth (l .Formatter .GetDepth ()+ 1 , args )
302
107
}
303
108
304
- // WithName returns a new logr.Logger with the specified name appended. glogr
305
- // uses '/' characters to separate name elements. Callers should not pass '/'
306
- // in the provided name string, but this library does not actually enforce that.
307
109
func (l glogger ) WithName (name string ) logr.LogSink {
308
- if len (l .prefix ) > 0 {
309
- l .prefix += "/"
310
- }
311
- l .prefix += name
110
+ l .Formatter .AddName (name )
312
111
return & l
313
112
}
314
113
315
114
func (l glogger ) WithValues (kvList ... interface {}) logr.LogSink {
316
- // Three slice args forces a copy.
317
- n := len (l .values )
318
- l .values = append (l .values [:n :n ], kvList ... )
115
+ l .Formatter .AddValues (kvList )
319
116
return & l
320
-
321
117
}
322
118
323
119
func (l glogger ) WithCallDepth (depth int ) logr.LogSink {
324
- l .depth += depth
120
+ l .Formatter . AddCallDepth ( depth )
325
121
return & l
326
-
327
122
}
0 commit comments