1
1
package errors
2
2
3
3
import (
4
+ "bytes"
4
5
"fmt"
5
6
"io"
6
7
"path"
@@ -49,6 +50,8 @@ func (f Frame) name() string {
49
50
return fn .Name ()
50
51
}
51
52
53
+ func (f Frame ) Format (s fmt.State , verb rune ) { f .format (s , s , verb ) }
54
+
52
55
// Format formats the frame according to the fmt.Formatter interface.
53
56
//
54
57
// %s source file
@@ -61,25 +64,25 @@ func (f Frame) name() string {
61
64
// %+s function name and path of source file relative to the compile time
62
65
// GOPATH separated by \n\t (<funcname>\n\t<path>)
63
66
// %+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 ) {
65
68
switch verb {
66
69
case 's' :
67
70
switch {
68
71
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 ())
72
75
default :
73
- io .WriteString (s , path .Base (f .file ()))
76
+ io .WriteString (w , path .Base (f .file ()))
74
77
}
75
78
case 'd' :
76
- io .WriteString (s , strconv .Itoa (f .line ()))
79
+ io .WriteString (w , strconv .Itoa (f .line ()))
77
80
case 'n' :
78
- io .WriteString (s , funcname (f .name ()))
81
+ io .WriteString (w , funcname (f .name ()))
79
82
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' )
83
86
}
84
87
}
85
88
@@ -141,11 +144,22 @@ func (st StackTrace) formatSlice(s fmt.State, verb rune) {
141
144
// stack represents a stack of program counters.
142
145
type stack []uintptr
143
146
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
+
144
152
func (s * stack ) Format (st fmt.State , verb rune ) {
145
153
if verb == 'v' && st .Flag ('+' ) {
154
+ var b = & bytes.Buffer {}
155
+ b .Grow (len (* s ) * stackMinLen )
156
+
146
157
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 )
148
160
}
161
+
162
+ io .Copy (st , b )
149
163
}
150
164
}
151
165
0 commit comments