11package errors
22
33import (
4+ "bytes"
45 "fmt"
56 "io"
67 "path"
@@ -49,6 +50,8 @@ func (f Frame) name() string {
4950 return fn .Name ()
5051}
5152
53+ func (f Frame ) Format (s fmt.State , verb rune ) { f .format (s , s , verb ) }
54+
5255// Format formats the frame according to the fmt.Formatter interface.
5356//
5457// %s source file
@@ -61,25 +64,25 @@ func (f Frame) name() string {
6164// %+s function name and path of source file relative to the compile time
6265// GOPATH separated by \n\t (<funcname>\n\t<path>)
6366// %+v equivalent to %+s:%d
64- func (f Frame ) Format ( s fmt.State , verb rune ) {
67+ func (f Frame ) format ( w io. Writer , s fmt.State , verb rune ) {
6568 switch verb {
6669 case 's' :
6770 switch {
6871 case s .Flag ('+' ):
69- io .WriteString (s , f .name ())
70- io .WriteString (s , "\n \t " )
71- io .WriteString (s , f .file ())
72+ io .WriteString (w , f .name ())
73+ io .WriteString (w , "\n \t " )
74+ io .WriteString (w , f .file ())
7275 default :
73- io .WriteString (s , path .Base (f .file ()))
76+ io .WriteString (w , path .Base (f .file ()))
7477 }
7578 case 'd' :
76- io .WriteString (s , strconv .Itoa (f .line ()))
79+ io .WriteString (w , strconv .Itoa (f .line ()))
7780 case 'n' :
78- io .WriteString (s , funcname (f .name ()))
81+ io .WriteString (w , funcname (f .name ()))
7982 case 'v' :
80- f .Format ( s , 's' )
81- io .WriteString (s , ":" )
82- f .Format ( s , 'd' )
83+ f .format ( w , s , 's' )
84+ io .WriteString (w , ":" )
85+ f .format ( w , s , 'd' )
8386 }
8487}
8588
@@ -141,11 +144,22 @@ func (st StackTrace) formatSlice(s fmt.State, verb rune) {
141144// stack represents a stack of program counters.
142145type stack []uintptr
143146
147+ // stackMinLen is a best-guess at the minimum length of a stack trace. It
148+ // doesn't need to be exact, just give a good enough head start for the buffer
149+ // to avoid the expensive early growth.
150+ const stackMinLen = 96
151+
144152func (s * stack ) Format (st fmt.State , verb rune ) {
145153 if verb == 'v' && st .Flag ('+' ) {
154+ var b = & bytes.Buffer {}
155+ b .Grow (len (* s ) * stackMinLen )
156+
146157 for i := range * s {
147- fmt .Fprintf (st , "\n %+v" , Frame ((* s )[i ]))
158+ b .WriteByte ('\n' )
159+ Frame ((* s )[i ]).format (b , st , verb )
148160 }
161+
162+ io .Copy (st , b )
149163 }
150164}
151165
0 commit comments