@@ -56,34 +56,34 @@ func reset(w io.Writer, termW io.Writer) {
5656 }
5757}
5858
59- func formatValue (v interface {}) string {
59+ func formatValue (v interface {}) ( string , error ) {
6060 if vr , ok := v .(driver.Valuer ); ok {
6161 var err error
6262 v , err = vr .Value ()
6363 if err != nil {
64- return fmt . Sprintf ("error calling Value: %v " , err )
64+ return "" , xerrors . Errorf ("error calling Value: %w " , err )
6565 }
6666 }
6767 if v == nil {
68- return "<nil>"
68+ return "<nil>" , nil
6969 }
7070 typ := reflect .TypeOf (v )
7171 switch typ .Kind () {
7272 case reflect .Struct , reflect .Map :
7373 byt , err := json .Marshal (v )
7474 if err != nil {
7575 // don't panic
76- return "!! Error while marshalling value !!"
76+ return "" , xerrors . Errorf ( "error marshalling value: %w" , err )
7777 }
78- return string (byt )
78+ return string (byt ), nil
7979 case reflect .Slice :
8080 // Byte slices are optimistically readable.
8181 if typ .Elem ().Kind () == reflect .Uint8 {
82- return fmt .Sprintf ("%q" , v )
82+ return fmt .Sprintf ("%q" , v ), nil
8383 }
8484 fallthrough
8585 default :
86- return quote (fmt .Sprintf ("%+v" , v ))
86+ return quote (fmt .Sprintf ("%+v" , v )), nil
8787 }
8888}
8989
@@ -175,6 +175,10 @@ func writeValueFast(w io.Writer, v interface{}) (bool, error) {
175175 }
176176}
177177
178+ type Formatter struct {
179+ ErrorCallback func (slog.Field , error )
180+ }
181+
178182// Fmt returns a human readable format for ent. Assumes we have a bytes.Buffer
179183// which we will more easily be able to assume underlying reallocation of it's size is possible
180184// if necessary than for an arbitrary io.Writer/io.StringWriter
@@ -188,6 +192,10 @@ func writeValueFast(w io.Writer, v interface{}) (bool, error) {
188192// for extra lines in a log so if we did it here, the fields would be indented
189193// twice in test logs. So the Stderr logger indents all the fields itself.
190194func Fmt (buf * bytes.Buffer , termW io.Writer , ent slog.SinkEntry ) {
195+ Formatter {}.Fmt (buf , termW , ent )
196+ }
197+
198+ func (f Formatter ) Fmt (buf * bytes.Buffer , termW io.Writer , ent slog.SinkEntry ) {
191199 reset (buf , termW )
192200
193201 // Timestamp + space
@@ -239,12 +247,12 @@ func Fmt(buf *bytes.Buffer, termW io.Writer, ent slog.SinkEntry) {
239247
240248 // Find a multiline field without mutating ent.Fields.
241249 multiIdx := - 1
242- for i , f := range ent .Fields {
250+ for i , fld := range ent .Fields {
243251 if multilineVal != "" {
244252 break
245253 }
246254 var s string
247- switch v := f .Value .(type ) {
255+ switch v := fld .Value .(type ) {
248256 case string :
249257 s = v
250258 case error , xerrors.Formatter :
@@ -255,27 +263,35 @@ func Fmt(buf *bytes.Buffer, termW io.Writer, ent slog.SinkEntry) {
255263 continue
256264 }
257265 multiIdx = i
258- multilineKey = f .Name
266+ multilineKey = fld .Name
259267 multilineVal = s
260268 break
261269 }
262270
263271 // Print fields (skip multiline field index).
264- for i , f := range ent .Fields {
272+ for i , fld := range ent .Fields {
265273 if i == multiIdx {
266274 continue
267275 }
268276 if i < len (ent .Fields ) {
269277 buf .WriteString (tab )
270278 }
271279
272- buf .WriteString (render (termW , keyStyle , quoteKey (f .Name )))
280+ buf .WriteString (render (termW , keyStyle , quoteKey (fld .Name )))
273281 buf .WriteString (render (termW , equalsStyle , "=" ))
274282
275- if ok , err := writeValueFast (buf , f .Value ); err != nil {
276- // return err
283+ if ok , err := writeValueFast (buf , fld .Value ); err != nil && f . ErrorCallback != nil {
284+ f . ErrorCallback ( fld , err )
277285 } else if ! ok {
278- buf .WriteString (formatValue (f .Value ))
286+ s , err := formatValue (fld .Value )
287+ if err != nil {
288+ if f .ErrorCallback != nil {
289+ f .ErrorCallback (fld , err )
290+ }
291+ buf .WriteString (err .Error ())
292+ continue
293+ }
294+ buf .WriteString (s )
279295 }
280296 }
281297
0 commit comments