github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zerror/format.go (about)

     1  package zerror
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"runtime"
     8  	"strings"
     9  
    10  	"github.com/sohaha/zlsgo/zutil"
    11  )
    12  
    13  // Error returns msg
    14  func (e *Error) Error() string {
    15  	if e == nil || (e.err == nil && e.errText == nil) {
    16  		return "<nil>"
    17  	}
    18  
    19  	if e.errText != nil {
    20  		return *e.errText
    21  	}
    22  
    23  	if e.inner && e.wrapErr != nil {
    24  		return e.wrapErr.Error()
    25  	}
    26  
    27  	return e.err.Error()
    28  }
    29  
    30  // Unwrap returns err inside
    31  func (e *Error) Unwrap() error {
    32  	if e == nil {
    33  		return nil
    34  	}
    35  	return e.wrapErr
    36  }
    37  
    38  // Format formats the frame according to the fmt.Formatter interface
    39  func (e *Error) Format(s fmt.State, verb rune) {
    40  	switch verb {
    41  	case 'v':
    42  		switch {
    43  		case s.Flag('-'):
    44  			_, _ = io.WriteString(s, e.Error())
    45  		default:
    46  			tip := strings.Join(UnwrapErrors(e), ": ")
    47  			_, _ = io.WriteString(s, tip+"\n"+e.Stack())
    48  		}
    49  	case 's':
    50  		_, _ = io.WriteString(s, strings.Join(UnwrapErrors(e), ": "))
    51  	}
    52  }
    53  
    54  // Stack returns the stack callers as string
    55  func (e *Error) Stack() string {
    56  	if e == nil {
    57  		return ""
    58  	}
    59  	loop, i, buffer := error(e), 1, zutil.GetBuff()
    60  	defer zutil.PutBuff(buffer)
    61  	for {
    62  		if loop == nil {
    63  			break
    64  		}
    65  		e, ok := loop.(*Error)
    66  		if ok {
    67  			if e.stack != nil {
    68  				if e.err != nil {
    69  					buffer.WriteString(fmt.Sprintf("%d. %-v\n", i, e.err))
    70  				} else {
    71  					buffer.WriteString(fmt.Sprintf("%d. %-v\n", i, e))
    72  				}
    73  				i++
    74  				formatSubStack(e.stack, buffer)
    75  			}
    76  			if e.wrapErr != nil {
    77  				if en, ok := e.wrapErr.(*Error); ok {
    78  					loop = en
    79  				} else {
    80  					loop = e.wrapErr
    81  					if loop == nil {
    82  						break
    83  					}
    84  					buffer.WriteString(fmt.Sprintf("%d. %s\n", i, loop.Error()))
    85  					break
    86  				}
    87  			} else {
    88  				break
    89  			}
    90  		}
    91  	}
    92  	return buffer.String()
    93  }
    94  
    95  // formatSubStack formats the stack for error
    96  func formatSubStack(st zutil.Stack, buffer *bytes.Buffer) {
    97  	if st == nil {
    98  		return
    99  	}
   100  	index := 1
   101  	space := "  "
   102  	st.Format(func(fn *runtime.Func, file string, line int) bool {
   103  		if strings.Contains(file, "<") {
   104  			return true
   105  		}
   106  		if goROOT != "" && strings.HasPrefix(file, goROOT) {
   107  			return true
   108  		}
   109  		if index > 9 {
   110  			space = " "
   111  		}
   112  
   113  		buffer.WriteString(fmt.Sprintf(
   114  			"   %d).%s%s\n    \t%s:%d\n",
   115  			index, space, fn.Name(), file, line,
   116  		))
   117  		index++
   118  		return true
   119  	})
   120  }