@@ -126,6 +126,14 @@ type Options struct {
126
126
// called for key-value pairs passed directly to Info and Error. See
127
127
// RenderBuiltinsHook for more details.
128
128
RenderArgsHook func (kvList []interface {}) []interface {}
129
+
130
+ // MaxLogDepth tells funcr how many levels of nested fields (e.g. a struct
131
+ // that contains a struct, etc.) it may log. Every time it finds a struct,
132
+ // slice, array, or map the depth is increased by one. When the maximum is
133
+ // reached, the value will be converted to a string indicating that the max
134
+ // depth has been exceeded. If this field is not specified, a default
135
+ // value will be used.
136
+ MaxLogDepth int
129
137
}
130
138
131
139
// MessageClass indicates which category or categories of messages to consider.
@@ -194,11 +202,15 @@ func NewFormatterJSON(opts Options) Formatter {
194
202
}
195
203
196
204
const defaultTimestampFmt = "2006-01-02 15:04:05.000000"
205
+ const defaultMaxDepth = 16
197
206
198
207
func newFormatter (opts Options , outfmt outputFormat ) Formatter {
199
208
if opts .TimestampFormat == "" {
200
209
opts .TimestampFormat = defaultTimestampFmt
201
210
}
211
+ if opts .MaxLogDepth == 0 {
212
+ opts .MaxLogDepth = defaultMaxDepth
213
+ }
202
214
f := Formatter {
203
215
outputFormat : outfmt ,
204
216
prefix : "" ,
@@ -321,15 +333,19 @@ func (f Formatter) flatten(buf *bytes.Buffer, kvList []interface{}, continuing b
321
333
}
322
334
323
335
func (f Formatter ) pretty (value interface {}) string {
324
- return f .prettyWithFlags (value , 0 )
336
+ return f .prettyWithFlags (value , 0 , 0 )
325
337
}
326
338
327
339
const (
328
340
flagRawStruct = 0x1 // do not print braces on structs
329
341
)
330
342
331
343
// TODO: This is not fast. Most of the overhead goes here.
332
- func (f Formatter ) prettyWithFlags (value interface {}, flags uint32 ) string {
344
+ func (f Formatter ) prettyWithFlags (value interface {}, flags uint32 , depth int ) string {
345
+ if depth > f .opts .MaxLogDepth {
346
+ return `"<max-log-depth-exceeded>"`
347
+ }
348
+
333
349
// Handle types that take full control of logging.
334
350
if v , ok := value .(logr.Marshaler ); ok {
335
351
// Replace the value with what the type wants to get logged.
@@ -394,7 +410,7 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32) string {
394
410
// arbitrary keys might need escaping
395
411
buf .WriteString (prettyString (v [i ].(string )))
396
412
buf .WriteByte (':' )
397
- buf .WriteString (f .pretty (v [i + 1 ]))
413
+ buf .WriteString (f .prettyWithFlags (v [i + 1 ], 0 , depth + 1 ))
398
414
}
399
415
if flags & flagRawStruct == 0 {
400
416
buf .WriteByte ('}' )
@@ -464,7 +480,7 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32) string {
464
480
buf .WriteByte (',' )
465
481
}
466
482
if fld .Anonymous && fld .Type .Kind () == reflect .Struct && name == "" {
467
- buf .WriteString (f .prettyWithFlags (v .Field (i ).Interface (), flags | flagRawStruct ))
483
+ buf .WriteString (f .prettyWithFlags (v .Field (i ).Interface (), flags | flagRawStruct , depth + 1 ))
468
484
continue
469
485
}
470
486
if name == "" {
@@ -475,7 +491,7 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32) string {
475
491
buf .WriteString (name )
476
492
buf .WriteByte ('"' )
477
493
buf .WriteByte (':' )
478
- buf .WriteString (f .pretty (v .Field (i ).Interface ()))
494
+ buf .WriteString (f .prettyWithFlags (v .Field (i ).Interface (), 0 , depth + 1 ))
479
495
}
480
496
if flags & flagRawStruct == 0 {
481
497
buf .WriteByte ('}' )
@@ -488,7 +504,7 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32) string {
488
504
buf .WriteByte (',' )
489
505
}
490
506
e := v .Index (i )
491
- buf .WriteString (f .pretty (e .Interface ()))
507
+ buf .WriteString (f .prettyWithFlags (e .Interface (), 0 , depth + 1 ))
492
508
}
493
509
buf .WriteByte (']' )
494
510
return buf .String ()
@@ -513,7 +529,7 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32) string {
513
529
keystr = prettyString (keystr )
514
530
} else {
515
531
// prettyWithFlags will produce already-escaped values
516
- keystr = f .prettyWithFlags (it .Key ().Interface (), 0 )
532
+ keystr = f .prettyWithFlags (it .Key ().Interface (), 0 , depth + 1 )
517
533
if t .Key ().Kind () != reflect .String {
518
534
// JSON only does string keys. Unlike Go's standard JSON, we'll
519
535
// convert just about anything to a string.
@@ -522,7 +538,7 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32) string {
522
538
}
523
539
buf .WriteString (keystr )
524
540
buf .WriteByte (':' )
525
- buf .WriteString (f .pretty (it .Value ().Interface ()))
541
+ buf .WriteString (f .prettyWithFlags (it .Value ().Interface (), 0 , depth + 1 ))
526
542
i ++
527
543
}
528
544
buf .WriteByte ('}' )
@@ -531,7 +547,7 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32) string {
531
547
if v .IsNil () {
532
548
return "null"
533
549
}
534
- return f .pretty (v .Elem ().Interface ())
550
+ return f .prettyWithFlags (v .Elem ().Interface (), 0 , depth )
535
551
}
536
552
return fmt .Sprintf (`"<unhandled-%s>"` , t .Kind ().String ())
537
553
}
0 commit comments