Codebase list golang-github-go-logr-logr / 9989c97
func: Make some free-funcs methods This is needed for upcoming changes. No behavioral code changes. Tim Hockin 2 years ago
2 changed file(s) with 47 addition(s) and 45 deletion(s). Raw diff Collapse all Expand all
134134 var _ logr.CallDepthLogSink = &fnlogger{}
135135 var _ Underlier = &fnlogger{}
136136
137 func flatten(kvList ...interface{}) string {
137 // NewFormatter constructs a Formatter.
138 func NewFormatter(opts Options) Formatter {
139 f := Formatter{
140 prefix: "",
141 values: nil,
142 depth: 0,
143 logCaller: opts.LogCaller,
144 logTimestamp: opts.LogTimestamp,
145 verbosity: opts.Verbosity,
146 }
147 return f
148 }
149
150 // Formatter is an opaque struct which can be embedded in a LogSink
151 // implementation. It should be constructed with NewFormatter. Some of
152 // its methods directly implement logr.LogSink.
153 type Formatter struct {
154 prefix string
155 values []interface{}
156 depth int
157 logCaller MessageClass
158 logTimestamp bool
159 verbosity int
160 }
161
162 func (f Formatter) flatten(kvList ...interface{}) string {
138163 if len(kvList)%2 != 0 {
139164 kvList = append(kvList, "<no-value>")
140165 }
154179 buf.WriteString(k)
155180 buf.WriteRune('"')
156181 buf.WriteRune('=')
157 buf.WriteString(pretty(v))
182 buf.WriteString(f.pretty(v))
158183 }
159184 return buf.String()
160185 }
161186
162 func pretty(value interface{}) string {
163 return prettyWithFlags(value, 0)
187 func (f Formatter) pretty(value interface{}) string {
188 return f.prettyWithFlags(value, 0)
164189 }
165190
166191 const (
168193 )
169194
170195 // TODO: This is not fast. Most of the overhead goes here.
171 func prettyWithFlags(value interface{}, flags uint32) string {
196 func (f Formatter) prettyWithFlags(value interface{}, flags uint32) string {
172197 // Handle types that take full control of logging.
173198 if v, ok := value.(logr.Marshaler); ok {
174199 // Replace the value with what the type wants to get logged.
256281 case reflect.Struct:
257282 buf.WriteRune('{')
258283 for i := 0; i < t.NumField(); i++ {
259 f := t.Field(i)
260 if f.PkgPath != "" {
284 fld := t.Field(i)
285 if fld.PkgPath != "" {
261286 // reflect says this field is only defined for non-exported fields.
262287 continue
263288 }
265290 buf.WriteRune(',')
266291 }
267292 buf.WriteRune('"')
268 name := f.Name
269 if tag, found := f.Tag.Lookup("json"); found {
293 name := fld.Name
294 if tag, found := fld.Tag.Lookup("json"); found {
270295 if comma := strings.Index(tag, ","); comma != -1 {
271296 name = tag[:comma]
272297 } else {
276301 buf.WriteString(name)
277302 buf.WriteRune('"')
278303 buf.WriteRune(':')
279 buf.WriteString(pretty(v.Field(i).Interface()))
304 buf.WriteString(f.pretty(v.Field(i).Interface()))
280305 }
281306 buf.WriteRune('}')
282307 return buf.String()
287312 buf.WriteRune(',')
288313 }
289314 e := v.Index(i)
290 buf.WriteString(pretty(e.Interface()))
315 buf.WriteString(f.pretty(e.Interface()))
291316 }
292317 buf.WriteRune(']')
293318 return buf.String()
302327 }
303328 // JSON only does string keys.
304329 buf.WriteRune('"')
305 buf.WriteString(prettyWithFlags(it.Key().Interface(), flagRawString))
330 buf.WriteString(f.prettyWithFlags(it.Key().Interface(), flagRawString))
306331 buf.WriteRune('"')
307332 buf.WriteRune(':')
308 buf.WriteString(pretty(it.Value().Interface()))
333 buf.WriteString(f.pretty(it.Value().Interface()))
309334 i++
310335 }
311336 buf.WriteRune('}')
314339 if v.IsNil() {
315340 return "null"
316341 }
317 return pretty(v.Elem().Interface())
342 return f.pretty(v.Elem().Interface())
318343 }
319344 return fmt.Sprintf(`"<unhandled-%s>"`, t.Kind().String())
320345 }
322347 type callerID struct {
323348 File string `json:"file"`
324349 Line int `json:"line"`
325 }
326
327 // NewFormatter constructs a Formatter.
328 func NewFormatter(opts Options) Formatter {
329 f := Formatter{
330 prefix: "",
331 values: nil,
332 depth: 0,
333 logCaller: opts.LogCaller,
334 logTimestamp: opts.LogTimestamp,
335 verbosity: opts.Verbosity,
336 }
337 return f
338 }
339
340 // Formatter is an opaque struct which can be embedded in a LogSink
341 // implementation. It should be constructed with NewFormatter. Some of
342 // its methods directly implement logr.LogSink.
343 type Formatter struct {
344 prefix string
345 values []interface{}
346 depth int
347 logCaller MessageClass
348 logTimestamp bool
349 verbosity int
350350 }
351351
352352 func (f Formatter) caller() callerID {
389389 args = append(args, "level", level, "msg", msg)
390390 args = append(args, f.values...)
391391 args = append(args, kvList...)
392 return f.prefix, flatten(args...)
392 return f.prefix, f.flatten(args...)
393393 }
394394
395395 // FormatError flattens an Error log message into strings.
410410 args = append(args, "error", loggableErr)
411411 args = append(args, f.values...)
412412 args = append(args, kvList...)
413 return f.prefix, flatten(args...)
413 return f.prefix, f.flatten(args...)
414414 }
415415
416416 // AddName appends the specified name. funcr uses '/' characters to separate
167167 },
168168 }
169169
170 f := NewFormatter(Options{})
170171 for i, tc := range cases {
171 ours := pretty(tc.val)
172 ours := f.pretty(tc.val)
172173 want := ""
173174 if tc.exp != "" {
174175 want = tc.exp
216217 expect: `"<non-string-key-0>"="val"`,
217218 }}
218219
219 for _, tc := range testCases {
220 t.Run(tc.name, func(t *testing.T) {
221 r := flatten(tc.kv...)
220 f := NewFormatter(Options{})
221 for _, tc := range testCases {
222 t.Run(tc.name, func(t *testing.T) {
223 r := f.flatten(tc.kv...)
222224 if r != tc.expect {
223225 t.Errorf("expected %q, got %q", tc.expect, r)
224226 }