stack.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package errors
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "path"
  7. "runtime"
  8. "strconv"
  9. "strings"
  10. )
  11. // Frame represents a program counter inside a stack frame.
  12. type Frame uintptr
  13. // pc returns the program counter for this frame;
  14. // multiple frames may have the same PC value.
  15. func (f Frame) pc() uintptr { return uintptr(f) - 1 }
  16. // file returns the full path to the file that contains the
  17. // function for this Frame's pc.
  18. func (f Frame) file() string {
  19. fn := runtime.FuncForPC(f.pc())
  20. if fn == nil {
  21. return "unknown"
  22. }
  23. file, _ := fn.FileLine(f.pc())
  24. return file
  25. }
  26. // line returns the line number of source code of the
  27. // function for this Frame's pc.
  28. func (f Frame) line() int {
  29. fn := runtime.FuncForPC(f.pc())
  30. if fn == nil {
  31. return 0
  32. }
  33. _, line := fn.FileLine(f.pc())
  34. return line
  35. }
  36. // Format formats the frame according to the fmt.Formatter interface.
  37. //
  38. // %s source file
  39. // %d source line
  40. // %n function name
  41. // %v equivalent to %s:%d
  42. //
  43. // Format accepts flags that alter the printing of some verbs, as follows:
  44. //
  45. // %+s function name and path of source file relative to the compile time
  46. // GOPATH separated by \n\t (<funcname>\n\t<path>)
  47. // %+v equivalent to %+s:%d
  48. func (f Frame) Format(s fmt.State, verb rune) {
  49. f.format(s, s, verb)
  50. }
  51. // format allows stack trace printing calls to be made with a bytes.Buffer.
  52. func (f Frame) format(w io.Writer, s fmt.State, verb rune) {
  53. switch verb {
  54. case 's':
  55. switch {
  56. case s.Flag('+'):
  57. pc := f.pc()
  58. fn := runtime.FuncForPC(pc)
  59. if fn == nil {
  60. io.WriteString(w, "unknown")
  61. } else {
  62. file, _ := fn.FileLine(pc)
  63. io.WriteString(w, fn.Name())
  64. io.WriteString(w, "\n\t")
  65. io.WriteString(w, file)
  66. }
  67. default:
  68. io.WriteString(w, path.Base(f.file()))
  69. }
  70. case 'd':
  71. io.WriteString(w, strconv.Itoa(f.line()))
  72. case 'n':
  73. name := runtime.FuncForPC(f.pc()).Name()
  74. io.WriteString(w, funcname(name))
  75. case 'v':
  76. f.format(w, s, 's')
  77. io.WriteString(w, ":")
  78. f.format(w, s, 'd')
  79. }
  80. }
  81. // StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
  82. type StackTrace []Frame
  83. // Format formats the stack of Frames according to the fmt.Formatter interface.
  84. //
  85. // %s lists source files for each Frame in the stack
  86. // %v lists the source file and line number for each Frame in the stack
  87. //
  88. // Format accepts flags that alter the printing of some verbs, as follows:
  89. //
  90. // %+v Prints filename, function, and line number for each Frame in the stack.
  91. func (st StackTrace) Format(s fmt.State, verb rune) {
  92. var b bytes.Buffer
  93. switch verb {
  94. case 'v':
  95. switch {
  96. case s.Flag('+'):
  97. b.Grow(len(st) * stackMinLen)
  98. for _, fr := range st {
  99. b.WriteByte('\n')
  100. fr.format(&b, s, verb)
  101. }
  102. case s.Flag('#'):
  103. fmt.Fprintf(&b, "%#v", []Frame(st))
  104. default:
  105. st.formatSlice(&b, s, verb)
  106. }
  107. case 's':
  108. st.formatSlice(&b, s, verb)
  109. }
  110. io.Copy(s, &b)
  111. }
  112. // formatSlice will format this StackTrace into the given buffer as a slice of
  113. // Frame, only valid when called with '%s' or '%v'.
  114. func (st StackTrace) formatSlice(b *bytes.Buffer, s fmt.State, verb rune) {
  115. b.WriteByte('[')
  116. if len(st) == 0 {
  117. b.WriteByte(']')
  118. return
  119. }
  120. b.Grow(len(st) * (stackMinLen / 4))
  121. st[0].format(b, s, verb)
  122. for _, fr := range st[1:] {
  123. b.WriteByte(' ')
  124. fr.format(b, s, verb)
  125. }
  126. b.WriteByte(']')
  127. }
  128. // stackMinLen is a best-guess at the minimum length of a stack trace. It
  129. // doesn't need to be exact, just give a good enough head start for the buffer
  130. // to avoid the expensive early growth.
  131. const stackMinLen = 96
  132. // stack represents a stack of program counters.
  133. type stack []uintptr
  134. func (s *stack) Format(st fmt.State, verb rune) {
  135. switch verb {
  136. case 'v':
  137. switch {
  138. case st.Flag('+'):
  139. var b bytes.Buffer
  140. b.Grow(len(*s) * stackMinLen)
  141. for _, pc := range *s {
  142. f := Frame(pc)
  143. b.WriteByte('\n')
  144. f.format(&b, st, 'v')
  145. }
  146. io.Copy(st, &b)
  147. }
  148. }
  149. }
  150. func (s *stack) StackTrace() StackTrace {
  151. f := make([]Frame, len(*s))
  152. for i := 0; i < len(f); i++ {
  153. f[i] = Frame((*s)[i])
  154. }
  155. return f
  156. }
  157. func callers() *stack {
  158. const depth = 32
  159. var pcs [depth]uintptr
  160. n := runtime.Callers(3, pcs[:])
  161. var st stack = pcs[0:n]
  162. return &st
  163. }
  164. // funcname removes the path prefix component of a function's name reported by func.Name().
  165. func funcname(name string) string {
  166. i := strings.LastIndex(name, "/")
  167. name = name[i+1:]
  168. i = strings.Index(name, ".")
  169. return name[i+1:]
  170. }