github.com/zly-app/zapp@v1.3.3/pkg/utils/recover.go (about)

     1  /*
     2  -------------------------------------------------
     3     Author :       Zhang Fan
     4     date:         2020/11/22
     5     Description :
     6  -------------------------------------------------
     7  */
     8  
     9  package utils
    10  
    11  import (
    12  	"errors"
    13  	"fmt"
    14  	"runtime"
    15  	"strings"
    16  )
    17  
    18  type Caller struct {
    19  	PC   uintptr
    20  	File string
    21  	Line int
    22  }
    23  
    24  type RecoverError interface {
    25  	error
    26  	Err() error
    27  	Callers() []*Caller
    28  }
    29  type recoverError struct {
    30  	err     error
    31  	callers []*Caller
    32  }
    33  
    34  func (r recoverError) Error() string {
    35  	return r.err.Error()
    36  }
    37  func (r recoverError) Err() error {
    38  	return r.err
    39  }
    40  func (r recoverError) Callers() []*Caller {
    41  	return r.callers
    42  }
    43  func newRecoverError(err error) RecoverError {
    44  	var callers []*Caller
    45  	for i := 3; ; i++ {
    46  		pc, file, line, got := runtime.Caller(i)
    47  		if !got {
    48  			break
    49  		}
    50  
    51  		callers = append(callers, &Caller{
    52  			PC:   pc,
    53  			File: file,
    54  			Line: line,
    55  		})
    56  	}
    57  
    58  	return recoverError{
    59  		err:     err,
    60  		callers: callers,
    61  	}
    62  }
    63  
    64  var Recover = new(recoverCli)
    65  
    66  type recoverCli struct{}
    67  
    68  func (*recoverCli) IsRecoverError(err error) bool {
    69  	_, ok := err.(RecoverError)
    70  	return ok
    71  }
    72  
    73  // 包装函数, 捕获panic
    74  func (*recoverCli) WrapCall(fn func() error) (err error) {
    75  	// 包装执行, 拦截panic
    76  	defer func() {
    77  		e := recover()
    78  		if e == nil {
    79  			return
    80  		}
    81  		switch v := e.(type) {
    82  		case error:
    83  			err = v
    84  		case string:
    85  			err = errors.New(v)
    86  		default:
    87  			err = errors.New(fmt.Sprint(e))
    88  		}
    89  		err = newRecoverError(err)
    90  	}()
    91  
    92  	err = fn()
    93  	return
    94  }
    95  
    96  // 获取 recover 错误
    97  func (*recoverCli) GetRecoverError(err error) (RecoverError, bool) {
    98  	re, ok := err.(RecoverError)
    99  	return re, ok
   100  }
   101  
   102  // 获取 recover 错误的详情
   103  func (*recoverCli) GetRecoverErrors(err error) []string {
   104  	re, ok := err.(RecoverError)
   105  	if !ok {
   106  		return []string{err.Error()}
   107  	}
   108  
   109  	var callers []string
   110  	callers = make([]string, len(re.Callers())+1)
   111  	callers[0] = err.Error()
   112  	for i, c := range re.Callers() {
   113  		callers[i+1] = fmt.Sprintf("%s:%d", c.File, c.Line)
   114  	}
   115  	return callers
   116  }
   117  
   118  // 获取 recover 错误的详情
   119  func (*recoverCli) GetRecoverErrorDetail(err error) string {
   120  	re, ok := err.(RecoverError)
   121  	if !ok {
   122  		return err.Error()
   123  	}
   124  
   125  	var callers []string
   126  	callers = make([]string, len(re.Callers())+1)
   127  	callers[0] = err.Error()
   128  	for i, c := range re.Callers() {
   129  		callers[i+1] = fmt.Sprintf("%s:%d", c.File, c.Line)
   130  	}
   131  	return strings.Join(callers, "\n")
   132  }