trpc.group/trpc-go/trpc-go@v1.0.3/errs/errs.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  // Package errs provides trpc error code type, which contains errcode errmsg.
    15  // These definitions are multi-language universal.
    16  package errs
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	"io"
    22  
    23  	trpcpb "trpc.group/trpc/trpc-protocol/pb/go/trpc"
    24  )
    25  
    26  // trpc return code.
    27  const (
    28  	// RetOK means success.
    29  	RetOK = trpcpb.TrpcRetCode_TRPC_INVOKE_SUCCESS
    30  
    31  	// RetServerDecodeFail is the error code of the server decoding error.
    32  	RetServerDecodeFail = trpcpb.TrpcRetCode_TRPC_SERVER_DECODE_ERR
    33  	// RetServerEncodeFail is the error code of the server encoding error.
    34  	RetServerEncodeFail = trpcpb.TrpcRetCode_TRPC_SERVER_ENCODE_ERR
    35  	// RetServerNoService is the error code that the server does not call the corresponding service implementation.
    36  	RetServerNoService = trpcpb.TrpcRetCode_TRPC_SERVER_NOSERVICE_ERR
    37  	// RetServerNoFunc is the error code that the server does not call the corresponding interface implementation.
    38  	RetServerNoFunc = trpcpb.TrpcRetCode_TRPC_SERVER_NOFUNC_ERR
    39  	// RetServerTimeout is the error code that the request timed out in the server queue.
    40  	RetServerTimeout = trpcpb.TrpcRetCode_TRPC_SERVER_TIMEOUT_ERR
    41  	// RetServerOverload is the error code that the request is overloaded on the server side.
    42  	RetServerOverload = trpcpb.TrpcRetCode_TRPC_SERVER_OVERLOAD_ERR
    43  	// RetServerThrottled is the error code of the server's current limit.
    44  	RetServerThrottled = trpcpb.TrpcRetCode_TRPC_SERVER_LIMITED_ERR
    45  	// RetServerFullLinkTimeout is the server full link timeout error code.
    46  	RetServerFullLinkTimeout = trpcpb.TrpcRetCode_TRPC_SERVER_FULL_LINK_TIMEOUT_ERR
    47  	// RetServerSystemErr is the error code of the server system error.
    48  	RetServerSystemErr = trpcpb.TrpcRetCode_TRPC_SERVER_SYSTEM_ERR
    49  	// RetServerAuthFail is the error code for authentication failure.
    50  	RetServerAuthFail = trpcpb.TrpcRetCode_TRPC_SERVER_AUTH_ERR
    51  	// RetServerValidateFail is the error code for the failure of automatic validation of request parameters.
    52  	RetServerValidateFail = trpcpb.TrpcRetCode_TRPC_SERVER_VALIDATE_ERR
    53  
    54  	// RetClientTimeout is the error code that the request timed out on the client side.
    55  	RetClientTimeout = trpcpb.TrpcRetCode_TRPC_CLIENT_INVOKE_TIMEOUT_ERR
    56  	// RetClientFullLinkTimeout is the client full link timeout error code.
    57  	RetClientFullLinkTimeout = trpcpb.TrpcRetCode_TRPC_CLIENT_FULL_LINK_TIMEOUT_ERR
    58  	// RetClientConnectFail is the error code of the client connection error.
    59  	RetClientConnectFail = trpcpb.TrpcRetCode_TRPC_CLIENT_CONNECT_ERR
    60  	// RetClientEncodeFail is the error code of the client encoding error.
    61  	RetClientEncodeFail = trpcpb.TrpcRetCode_TRPC_CLIENT_ENCODE_ERR
    62  	// RetClientDecodeFail is the error code of the client decoding error.
    63  	RetClientDecodeFail = trpcpb.TrpcRetCode_TRPC_CLIENT_DECODE_ERR
    64  	// RetClientThrottled is the error code of the client's current limit.
    65  	RetClientThrottled = trpcpb.TrpcRetCode_TRPC_CLIENT_LIMITED_ERR
    66  	// RetClientOverload is the error code for client overload.
    67  	RetClientOverload = trpcpb.TrpcRetCode_TRPC_CLIENT_OVERLOAD_ERR
    68  	// RetClientRouteErr is the error code for the wrong ip route selected by the client.
    69  	RetClientRouteErr = trpcpb.TrpcRetCode_TRPC_CLIENT_ROUTER_ERR
    70  	// RetClientNetErr is the error code of the client network error.
    71  	RetClientNetErr = trpcpb.TrpcRetCode_TRPC_CLIENT_NETWORK_ERR
    72  	// RetClientValidateFail is the error code for the failure of automatic validation of response parameters.
    73  	RetClientValidateFail = trpcpb.TrpcRetCode_TRPC_CLIENT_VALIDATE_ERR
    74  	// RetClientCanceled is the error code for the upstream caller to cancel the request in advance.
    75  	RetClientCanceled = trpcpb.TrpcRetCode_TRPC_CLIENT_CANCELED_ERR
    76  	// RetClientReadFrameErr is the error code of the client read frame error.
    77  	RetClientReadFrameErr = trpcpb.TrpcRetCode_TRPC_CLIENT_READ_FRAME_ERR
    78  	// RetClientStreamQueueFull is the error code of the client stream queue full.
    79  	RetClientStreamQueueFull = trpcpb.TrpcRetCode_TRPC_STREAM_SERVER_NETWORK_ERR
    80  	// RetClientStreamReadEnd is the error code of the client stream end error while receiving data.
    81  	RetClientStreamReadEnd = trpcpb.TrpcRetCode_TRPC_STREAM_CLIENT_READ_END
    82  
    83  	// RetUnknown is the error code for unspecified errors.
    84  	RetUnknown = trpcpb.TrpcRetCode_TRPC_INVOKE_UNKNOWN_ERR
    85  )
    86  
    87  // Err frame error value.
    88  var (
    89  	// ErrOK means success.
    90  	ErrOK error
    91  
    92  	// ErrServerNoService is an error that the server does not call the corresponding service implementation.
    93  	ErrServerNoService = NewFrameError(RetServerNoService, "server router no service")
    94  	// ErrServerNoFunc is an error that the server does not call the corresponding interface implementation.
    95  	ErrServerNoFunc = NewFrameError(RetServerNoFunc, "server router no rpc method")
    96  	// ErrServerTimeout is the error that the request timed out in the server queue.
    97  	ErrServerTimeout = NewFrameError(RetServerTimeout, "server message handle timeout")
    98  	// ErrServerOverload is an error that the request is overloaded on the server side.
    99  	ErrServerOverload = NewFrameError(RetServerOverload, "server overload")
   100  	// ErrServerRoutinePoolBusy is an error that the request is overloaded on the server side.
   101  	ErrServerRoutinePoolBusy = NewFrameError(RetServerOverload, "server goroutine pool too small")
   102  	// ErrServerClose is a server system error.
   103  	ErrServerClose = NewFrameError(RetServerSystemErr, "server close")
   104  
   105  	// ErrServerNoResponse is a server-side unresponsive error.
   106  	ErrServerNoResponse = NewFrameError(RetOK, "server no response")
   107  	// ErrClientNoResponse is the error of the client not responding.
   108  	ErrClientNoResponse = NewFrameError(RetOK, "client no response")
   109  
   110  	// ErrUnknown is an unknown error.
   111  	ErrUnknown = NewFrameError(RetUnknown, "unknown error")
   112  )
   113  
   114  // ErrorType is the error code type, including framework error code and business error code.
   115  const (
   116  	ErrorTypeFramework       = 1
   117  	ErrorTypeBusiness        = 2
   118  	ErrorTypeCalleeFramework = 3 // The error code returned by the client call
   119  	// represents the downstream framework error code.
   120  )
   121  
   122  func typeDesc(t int) string {
   123  	switch t {
   124  	case ErrorTypeFramework:
   125  		return "framework"
   126  	case ErrorTypeCalleeFramework:
   127  		return "callee framework"
   128  	default:
   129  		return "business"
   130  	}
   131  }
   132  
   133  const (
   134  	// Success is the success prompt string.
   135  	Success = "success"
   136  )
   137  
   138  // Error is the error code structure which contains error code type and error message.
   139  type Error struct {
   140  	Type int
   141  	Code trpcpb.TrpcRetCode
   142  	Msg  string
   143  	Desc string
   144  
   145  	cause error      // internal error, form the error chain.
   146  	stack stackTrace // call stack, if the error chain already has a stack, it will not be set.
   147  }
   148  
   149  // Error implements the error interface and returns the error description.
   150  func (e *Error) Error() string {
   151  	if e == nil {
   152  		return Success
   153  	}
   154  
   155  	if e.cause != nil {
   156  		return fmt.Sprintf("type:%s, code:%d, msg:%s, caused by %s",
   157  			typeDesc(e.Type), e.Code, e.Msg, e.cause.Error())
   158  	}
   159  	return fmt.Sprintf("type:%s, code:%d, msg:%s", typeDesc(e.Type), e.Code, e.Msg)
   160  }
   161  
   162  // Format implements the fmt.Formatter interface.
   163  func (e *Error) Format(s fmt.State, verb rune) {
   164  	var stackTrace stackTrace
   165  	defer func() {
   166  		if stackTrace != nil {
   167  			stackTrace.Format(s, verb)
   168  		}
   169  	}()
   170  	switch verb {
   171  	case 'v':
   172  		if s.Flag('+') {
   173  			_, _ = fmt.Fprintf(s, "type:%s, code:%d, msg:%s", typeDesc(e.Type), e.Code, e.Msg)
   174  			if e.stack != nil {
   175  				stackTrace = e.stack
   176  			}
   177  			if e.Unwrap() != nil {
   178  				_, _ = fmt.Fprintf(s, "\nCause by %+v", e.Unwrap())
   179  			}
   180  			return
   181  		}
   182  		fallthrough
   183  	case 's':
   184  		_, _ = io.WriteString(s, e.Error())
   185  	case 'q':
   186  		_, _ = fmt.Fprintf(s, "%q", e.Error())
   187  	default:
   188  		_, _ = fmt.Fprintf(s, "%%!%c(errs.Error=%s)", verb, e.Error())
   189  	}
   190  }
   191  
   192  // Unwrap support Go 1.13+ error chains.
   193  func (e *Error) Unwrap() error { return e.cause }
   194  
   195  // IsTimeout checks whether this error is a timeout error with error type typ.
   196  func (e *Error) IsTimeout(typ int) bool {
   197  	return e.Type == typ &&
   198  		(e.Code == RetClientTimeout ||
   199  			e.Code == RetClientFullLinkTimeout ||
   200  			e.Code == RetServerTimeout ||
   201  			e.Code == RetServerFullLinkTimeout)
   202  }
   203  
   204  // ErrCode permits any integer defined in https://go.dev/ref/spec#Numeric_types
   205  type ErrCode interface {
   206  	~uint8 | ~uint16 | ~uint32 | ~uint64 | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~int | ~uintptr
   207  }
   208  
   209  // New creates an error, which defaults to the business error type to improve business development efficiency.
   210  func New[T ErrCode](code T, msg string) error {
   211  	err := &Error{
   212  		Type: ErrorTypeBusiness,
   213  		Code: trpcpb.TrpcRetCode(code),
   214  		Msg:  msg,
   215  	}
   216  	if traceable {
   217  		err.stack = callers()
   218  	}
   219  	return err
   220  }
   221  
   222  // Newf creates an error, the default is the business error type, msg supports format strings.
   223  func Newf[T ErrCode](code T, format string, params ...interface{}) error {
   224  	msg := fmt.Sprintf(format, params...)
   225  	err := &Error{
   226  		Type: ErrorTypeBusiness,
   227  		Code: trpcpb.TrpcRetCode(code),
   228  		Msg:  msg,
   229  	}
   230  	if traceable {
   231  		err.stack = callers()
   232  	}
   233  	return err
   234  }
   235  
   236  // Wrap creates a new error contains input error.
   237  // only add stack when traceable is true and the input type is not Error, this will ensure that there is no multiple
   238  // stacks in the error chain.
   239  func Wrap[T ErrCode](err error, code T, msg string) error {
   240  	if err == nil {
   241  		return nil
   242  	}
   243  	wrapErr := &Error{
   244  		Type:  ErrorTypeBusiness,
   245  		Code:  trpcpb.TrpcRetCode(code),
   246  		Msg:   msg,
   247  		cause: err,
   248  	}
   249  	var e *Error
   250  	// the error chain does not contain item which type is Error, add stack.
   251  	if traceable && !errors.As(err, &e) {
   252  		wrapErr.stack = callers()
   253  	}
   254  	return wrapErr
   255  }
   256  
   257  // Wrapf the same as Wrap, msg supports format strings.
   258  func Wrapf[T ErrCode](err error, code T, format string, params ...interface{}) error {
   259  	if err == nil {
   260  		return nil
   261  	}
   262  	msg := fmt.Sprintf(format, params...)
   263  	wrapErr := &Error{
   264  		Type:  ErrorTypeBusiness,
   265  		Code:  trpcpb.TrpcRetCode(code),
   266  		Msg:   msg,
   267  		cause: err,
   268  	}
   269  	var e *Error
   270  	// the error chain does not contain item which type is Error, add stack.
   271  	if traceable && !errors.As(err, &e) {
   272  		wrapErr.stack = callers()
   273  	}
   274  	return wrapErr
   275  }
   276  
   277  // NewFrameError creates a frame error.
   278  func NewFrameError[T ErrCode](code T, msg string) error {
   279  	err := &Error{
   280  		Type: ErrorTypeFramework,
   281  		Code: trpcpb.TrpcRetCode(code),
   282  		Msg:  msg,
   283  		Desc: "trpc",
   284  	}
   285  	if traceable {
   286  		err.stack = callers()
   287  	}
   288  	return err
   289  }
   290  
   291  // WrapFrameError the same as Wrap, except type is ErrorTypeFramework
   292  func WrapFrameError[T ErrCode](err error, code T, msg string) error {
   293  	if err == nil {
   294  		return nil
   295  	}
   296  	wrapErr := &Error{
   297  		Type:  ErrorTypeFramework,
   298  		Code:  trpcpb.TrpcRetCode(code),
   299  		Msg:   msg,
   300  		Desc:  "trpc",
   301  		cause: err,
   302  	}
   303  	var e *Error
   304  	// the error chain does not contain item which type is Error, add stack.
   305  	if traceable && !errors.As(err, &e) {
   306  		wrapErr.stack = callers()
   307  	}
   308  	return wrapErr
   309  }
   310  
   311  // Code gets the error code through error.
   312  func Code(e error) trpcpb.TrpcRetCode {
   313  	if e == nil {
   314  		return RetOK
   315  	}
   316  
   317  	// Doing type assertion first has a slight performance boost over just using errors.As
   318  	// because of avoiding reflect when the assertion is probably true.
   319  	err, ok := e.(*Error)
   320  	if !ok && !errors.As(e, &err) {
   321  		return RetUnknown
   322  	}
   323  	if err == nil {
   324  		return RetOK
   325  	}
   326  	return err.Code
   327  }
   328  
   329  // Msg gets error msg through error.
   330  func Msg(e error) string {
   331  	if e == nil {
   332  		return Success
   333  	}
   334  	err, ok := e.(*Error)
   335  	if !ok && !errors.As(e, &err) {
   336  		return e.Error()
   337  	}
   338  	if err == (*Error)(nil) {
   339  		return Success
   340  	}
   341  	// For cases of error chains, err.Error() will print the entire chain,
   342  	// including the current error and the nested error messages, in an appropriate format.
   343  	if err.Unwrap() != nil {
   344  		return err.Error()
   345  	}
   346  	return err.Msg
   347  }