github.com/nyan233/littlerpc@v0.4.6-0.20230316182519-0c8d5c48abaf/core/common/errorhandler/errorhandler.go (about)

     1  package errorhandler
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	error2 "github.com/nyan233/littlerpc/core/protocol/error"
     7  	"github.com/nyan233/littlerpc/core/utils/convert"
     8  	"runtime"
     9  	"strings"
    10  )
    11  
    12  // DefaultErrHandler 不带栈追踪的默认错误处理器
    13  var DefaultErrHandler = New()
    14  
    15  type marshalStack struct {
    16  	Stack stack `json:"stack"`
    17  }
    18  
    19  type stack []string
    20  
    21  func (s stack) MarshalJSON() ([]byte, error) {
    22  	if s == nil {
    23  		return []byte("null"), nil
    24  	}
    25  	var sb strings.Builder
    26  	sb.WriteByte('[')
    27  	for i := len(s) - 1; i >= 0; i-- {
    28  		sb.WriteByte('"')
    29  		sb.WriteString(s[i])
    30  		sb.WriteByte('"')
    31  		if i != 0 {
    32  			sb.WriteByte(',')
    33  		}
    34  	}
    35  	sb.WriteByte(']')
    36  	return convert.StringToBytes(sb.String()), nil
    37  }
    38  
    39  type lRPCStackTraceError struct {
    40  	RpcCode    int           `json:"code"`
    41  	RpcMessage string        `json:"message"`
    42  	RpcMores   []interface{} `json:"mores"`
    43  	RpcStack   stack         `json:"stack"`
    44  }
    45  
    46  func error2LRPCError(err error2.LErrorDesc) *lRPCStackTraceError {
    47  	return &lRPCStackTraceError{
    48  		RpcCode:    err.Code(),
    49  		RpcMessage: err.Message(),
    50  		RpcMores:   append(err.Mores()),
    51  		RpcStack:   make([]string, 0, 8),
    52  	}
    53  }
    54  
    55  func warpStackTraceError(err *lRPCStackTraceError, mores ...interface{}) *lRPCStackTraceError {
    56  	return &lRPCStackTraceError{
    57  		RpcCode:    err.RpcCode,
    58  		RpcMessage: err.RpcMessage,
    59  		RpcMores:   append(err.RpcMores, mores...),
    60  		RpcStack:   err.RpcStack,
    61  	}
    62  }
    63  
    64  func (l *lRPCStackTraceError) Code() int {
    65  	return l.RpcCode
    66  }
    67  
    68  func (l *lRPCStackTraceError) Message() string {
    69  	return l.RpcMessage
    70  }
    71  
    72  func (l *lRPCStackTraceError) AppendMore(more interface{}) {
    73  	l.RpcMores = append(l.RpcMores, more)
    74  }
    75  
    76  func (l *lRPCStackTraceError) Mores() []interface{} {
    77  	return l.RpcMores
    78  }
    79  
    80  func (l *lRPCStackTraceError) MarshalMores() ([]byte, error) {
    81  	mores := l.Mores()
    82  	mores = append(mores, &marshalStack{Stack: l.RpcStack})
    83  	return json.Marshal(mores)
    84  }
    85  
    86  func (l *lRPCStackTraceError) UnmarshalMores(bytes []byte) error {
    87  	return json.Unmarshal(bytes, &l.RpcMores)
    88  }
    89  
    90  func (l *lRPCStackTraceError) Error() string {
    91  	type PrintError struct {
    92  		RpcCode    int           `json:"code"`
    93  		RpcMessage string        `json:"message"`
    94  		RpcMores   []interface{} `json:"mores"`
    95  	}
    96  	mores := l.Mores()
    97  	mores = append(mores, &marshalStack{Stack: l.RpcStack})
    98  	bytes, err := json.Marshal(&PrintError{
    99  		RpcCode:    l.Code(),
   100  		RpcMessage: l.Message(),
   101  		RpcMores:   mores,
   102  	})
   103  	if err != nil {
   104  		panic("json.Marshal failed : " + err.Error())
   105  	}
   106  	return convert.BytesToString(bytes)
   107  }
   108  
   109  type JsonErrorHandler struct {
   110  	openStackTrace bool
   111  }
   112  
   113  func NewStackTrace() error2.LErrors {
   114  	return &JsonErrorHandler{
   115  		openStackTrace: true,
   116  	}
   117  }
   118  
   119  func New() error2.LErrors {
   120  	return new(JsonErrorHandler)
   121  }
   122  
   123  func (j JsonErrorHandler) LNewErrorDesc(code int, message string, mores ...interface{}) error2.LErrorDesc {
   124  	if !j.openStackTrace {
   125  		return error2.LNewStdError(code, message, mores...)
   126  	}
   127  	err := error2LRPCError(error2.LNewStdError(code, message, mores...))
   128  	// runtime.Caller即使有重复的代码也不能抽到公共函数中, skip参数对性能的影响很大
   129  	_, file, line, ok := runtime.Caller(1)
   130  	if !ok {
   131  		err.RpcStack = append(err.RpcStack, "???.go:???")
   132  	} else {
   133  		err.RpcStack = append(err.RpcStack, fmt.Sprintf("%s:%d", file, line))
   134  	}
   135  	return err
   136  }
   137  
   138  func (j JsonErrorHandler) LWarpErrorDesc(desc error2.LErrorDesc, mores ...interface{}) error2.LErrorDesc {
   139  	if !j.openStackTrace {
   140  		return error2.LWarpStdError(desc, mores...)
   141  	}
   142  	err, _ := desc.(*lRPCStackTraceError)
   143  	if err == nil {
   144  		err = error2LRPCError(error2.LWarpStdError(desc, mores...))
   145  	} else {
   146  		err = warpStackTraceError(err, mores...)
   147  	}
   148  	// runtime.Caller即使有重复的代码也不能抽到公共函数中, skip参数对性能的影响很大
   149  	_, file, line, ok := runtime.Caller(1)
   150  	if !ok {
   151  		err.RpcStack = append(err.RpcStack, "???.go:???")
   152  	} else {
   153  		err.RpcStack = append(err.RpcStack, fmt.Sprintf("%s:%d", file, line))
   154  	}
   155  	return err
   156  }