vendor/github.com/pkg/errors/stack.go
changeset 251 1c52a0eeb952
parent 246 0998f404dd31
equal deleted inserted replaced
250:c040f992052f 251:1c52a0eeb952
     3 import (
     3 import (
     4 	"fmt"
     4 	"fmt"
     5 	"io"
     5 	"io"
     6 	"path"
     6 	"path"
     7 	"runtime"
     7 	"runtime"
       
     8 	"strconv"
     8 	"strings"
     9 	"strings"
     9 )
    10 )
    10 
    11 
    11 // Frame represents a program counter inside a stack frame.
    12 // Frame represents a program counter inside a stack frame.
       
    13 // For historical reasons if Frame is interpreted as a uintptr
       
    14 // its value represents the program counter + 1.
    12 type Frame uintptr
    15 type Frame uintptr
    13 
    16 
    14 // pc returns the program counter for this frame;
    17 // pc returns the program counter for this frame;
    15 // multiple frames may have the same PC value.
    18 // multiple frames may have the same PC value.
    16 func (f Frame) pc() uintptr { return uintptr(f) - 1 }
    19 func (f Frame) pc() uintptr { return uintptr(f) - 1 }
    35 	}
    38 	}
    36 	_, line := fn.FileLine(f.pc())
    39 	_, line := fn.FileLine(f.pc())
    37 	return line
    40 	return line
    38 }
    41 }
    39 
    42 
       
    43 // name returns the name of this function, if known.
       
    44 func (f Frame) name() string {
       
    45 	fn := runtime.FuncForPC(f.pc())
       
    46 	if fn == nil {
       
    47 		return "unknown"
       
    48 	}
       
    49 	return fn.Name()
       
    50 }
       
    51 
    40 // Format formats the frame according to the fmt.Formatter interface.
    52 // Format formats the frame according to the fmt.Formatter interface.
    41 //
    53 //
    42 //    %s    source file
    54 //    %s    source file
    43 //    %d    source line
    55 //    %d    source line
    44 //    %n    function name
    56 //    %n    function name
    52 func (f Frame) Format(s fmt.State, verb rune) {
    64 func (f Frame) Format(s fmt.State, verb rune) {
    53 	switch verb {
    65 	switch verb {
    54 	case 's':
    66 	case 's':
    55 		switch {
    67 		switch {
    56 		case s.Flag('+'):
    68 		case s.Flag('+'):
    57 			pc := f.pc()
    69 			io.WriteString(s, f.name())
    58 			fn := runtime.FuncForPC(pc)
    70 			io.WriteString(s, "\n\t")
    59 			if fn == nil {
    71 			io.WriteString(s, f.file())
    60 				io.WriteString(s, "unknown")
       
    61 			} else {
       
    62 				file, _ := fn.FileLine(pc)
       
    63 				fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
       
    64 			}
       
    65 		default:
    72 		default:
    66 			io.WriteString(s, path.Base(f.file()))
    73 			io.WriteString(s, path.Base(f.file()))
    67 		}
    74 		}
    68 	case 'd':
    75 	case 'd':
    69 		fmt.Fprintf(s, "%d", f.line())
    76 		io.WriteString(s, strconv.Itoa(f.line()))
    70 	case 'n':
    77 	case 'n':
    71 		name := runtime.FuncForPC(f.pc()).Name()
    78 		io.WriteString(s, funcname(f.name()))
    72 		io.WriteString(s, funcname(name))
       
    73 	case 'v':
    79 	case 'v':
    74 		f.Format(s, 's')
    80 		f.Format(s, 's')
    75 		io.WriteString(s, ":")
    81 		io.WriteString(s, ":")
    76 		f.Format(s, 'd')
    82 		f.Format(s, 'd')
    77 	}
    83 	}
       
    84 }
       
    85 
       
    86 // MarshalText formats a stacktrace Frame as a text string. The output is the
       
    87 // same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
       
    88 func (f Frame) MarshalText() ([]byte, error) {
       
    89 	name := f.name()
       
    90 	if name == "unknown" {
       
    91 		return []byte(name), nil
       
    92 	}
       
    93 	return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
    78 }
    94 }
    79 
    95 
    80 // StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
    96 // StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
    81 type StackTrace []Frame
    97 type StackTrace []Frame
    82 
    98 
    92 	switch verb {
   108 	switch verb {
    93 	case 'v':
   109 	case 'v':
    94 		switch {
   110 		switch {
    95 		case s.Flag('+'):
   111 		case s.Flag('+'):
    96 			for _, f := range st {
   112 			for _, f := range st {
    97 				fmt.Fprintf(s, "\n%+v", f)
   113 				io.WriteString(s, "\n")
       
   114 				f.Format(s, verb)
    98 			}
   115 			}
    99 		case s.Flag('#'):
   116 		case s.Flag('#'):
   100 			fmt.Fprintf(s, "%#v", []Frame(st))
   117 			fmt.Fprintf(s, "%#v", []Frame(st))
   101 		default:
   118 		default:
   102 			fmt.Fprintf(s, "%v", []Frame(st))
   119 			st.formatSlice(s, verb)
   103 		}
   120 		}
   104 	case 's':
   121 	case 's':
   105 		fmt.Fprintf(s, "%s", []Frame(st))
   122 		st.formatSlice(s, verb)
   106 	}
   123 	}
       
   124 }
       
   125 
       
   126 // formatSlice will format this StackTrace into the given buffer as a slice of
       
   127 // Frame, only valid when called with '%s' or '%v'.
       
   128 func (st StackTrace) formatSlice(s fmt.State, verb rune) {
       
   129 	io.WriteString(s, "[")
       
   130 	for i, f := range st {
       
   131 		if i > 0 {
       
   132 			io.WriteString(s, " ")
       
   133 		}
       
   134 		f.Format(s, verb)
       
   135 	}
       
   136 	io.WriteString(s, "]")
   107 }
   137 }
   108 
   138 
   109 // stack represents a stack of program counters.
   139 // stack represents a stack of program counters.
   110 type stack []uintptr
   140 type stack []uintptr
   111 
   141