123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- package errors
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "strings"
- )
- type formatInfo struct {
- code int
- message string
- err string
- stack *stack
- }
- func (w *withCode) Format(state fmt.State, verb rune) {
- switch verb {
- case 'v':
- str := bytes.NewBuffer([]byte{})
- jsonData := []map[string]interface{}{}
- var (
- flagDetail bool
- flagTrace bool
- modeJSON bool
- )
- if state.Flag('#') {
- modeJSON = true
- }
- if state.Flag('-') {
- flagDetail = true
- }
- if state.Flag('+') {
- flagTrace = true
- }
- sep := ""
- errs := list(w)
- length := len(errs)
- for k, e := range errs {
- finfo := buildFormatInfo(e)
- jsonData, str = format(length-k-1, jsonData, str, finfo, sep, flagDetail, flagTrace, modeJSON)
- sep = "; "
- if !flagTrace {
- break
- }
- if !flagDetail && !flagTrace && !modeJSON {
- break
- }
- }
- if modeJSON {
- var byts []byte
- byts, _ = json.Marshal(jsonData)
- str.Write(byts)
- }
- fmt.Fprintf(state, "%s", strings.Trim(str.String(), "\r\n\t"))
- default:
- finfo := buildFormatInfo(w)
- // Externally-safe error message
- fmt.Fprintf(state, finfo.message)
- }
- }
- func format(k int, jsonData []map[string]interface{}, str *bytes.Buffer, finfo *formatInfo,
- sep string, flagDetail, flagTrace, modeJSON bool) ([]map[string]interface{}, *bytes.Buffer) {
- if modeJSON {
- data := map[string]interface{}{}
- if flagDetail || flagTrace {
- data = map[string]interface{}{
- "message": finfo.message,
- "code": finfo.code,
- "error": finfo.err,
- }
- caller := fmt.Sprintf("#%d", k)
- if finfo.stack != nil {
- f := Frame((*finfo.stack)[0])
- caller = fmt.Sprintf("%s %s:%d (%s)",
- caller,
- f.file(),
- f.line(),
- f.name(),
- )
- }
- data["caller"] = caller
- } else {
- data["error"] = finfo.message
- }
- jsonData = append(jsonData, data)
- } else {
- if flagDetail || flagTrace {
- if finfo.stack != nil {
- f := Frame((*finfo.stack)[0])
- fmt.Fprintf(str, "%s%s - #%d [%s:%d (%s)] (%d) %s",
- sep,
- finfo.err,
- k,
- f.file(),
- f.line(),
- f.name(),
- finfo.code,
- finfo.message,
- )
- } else {
- fmt.Fprintf(str, "%s%s - #%d %s", sep, finfo.err, k, finfo.message)
- }
- } else {
- fmt.Fprintf(str, finfo.message)
- }
- }
- return jsonData, str
- }
- func list(e error) []error {
- var ret []error
- if e != nil {
- if w, ok := e.(interface{ Unwrap() error }); ok {
- ret = append(ret, e)
- ret = append(ret, list(w.Unwrap())...)
- } else {
- ret = append(ret, e)
- }
- }
- return ret
- }
- func buildFormatInfo(e error) *formatInfo {
- var finfo *formatInfo
- err, ok := e.(*withCode)
- if !ok {
- return &formatInfo{
- code: unknownCoder.Code(),
- message: err.Error(),
- err: err.Error(),
- }
- }
- coder, ok := codes[err.code]
- if !ok {
- coder = unknownCoder
- }
- extMsg := coder.String()
- if extMsg == "" {
- extMsg = err.err.Error()
- }
- finfo = &formatInfo{
- code: coder.Code(),
- message: extMsg,
- err: err.err.Error(),
- stack: err.stack,
- }
- return finfo
- }
|