github.com/songzhibin97/gkit@v1.2.13/errors/error.go (about)

     1  package errors
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/golang/protobuf/proto"
     8  	httputil "github.com/songzhibin97/gkit/errors/internal"
     9  	"google.golang.org/genproto/googleapis/rpc/errdetails"
    10  	"google.golang.org/grpc/status"
    11  )
    12  
    13  //go:generate protoc -I. --go_out=paths=source_relative:. errors.proto
    14  
    15  const (
    16  	// UnknownCode is unknown code for error info.
    17  	UnknownCode = 500
    18  	// UnknownReason is unknown reason for error info.
    19  	UnknownReason = ""
    20  )
    21  
    22  var ErrDetails = errors.New("no error details for status with code OK")
    23  
    24  // Error 实现Error接口
    25  func (x *Error) Error() string {
    26  	return fmt.Sprintf("error: code = %d reason = %s message = %s details = %v", x.Code, x.Reason, x.Message, x.Metadata)
    27  }
    28  
    29  // StatusCode HTTP code
    30  func (x *Error) StatusCode() int {
    31  	return int(x.Code)
    32  }
    33  
    34  // GRPCStatus 返回grpc status
    35  func (x *Error) GRPCStatus() *status.Status {
    36  	s, _ := status.New(httputil.GRPCCodeFromStatus(x.StatusCode()), x.Message).
    37  		WithDetails(&errdetails.ErrorInfo{
    38  			Reason:   x.Reason,
    39  			Metadata: x.Metadata,
    40  		})
    41  	return s
    42  }
    43  
    44  // Is 跟 target Error 比较 判断是否相等
    45  func (x *Error) Is(target error) bool {
    46  	if err, ok := target.(*Error); !ok {
    47  		return false
    48  	} else {
    49  		return x.Code == err.Code
    50  	}
    51  }
    52  
    53  // AddMetadata 增加metadata
    54  func (x *Error) AddMetadata(mp map[string]string) *Error {
    55  	err := proto.Clone(x).(*Error)
    56  	err.Metadata = mp
    57  	return err
    58  }
    59  
    60  // New 实例化 Error 对象
    61  func New(code int, reason, message string) *Error {
    62  	return &Error{
    63  		Code:    int32(code),
    64  		Reason:  reason,
    65  		Message: message,
    66  	}
    67  }
    68  
    69  func Errorf(code int, reason, format string, a ...interface{}) *Error {
    70  	return New(code, reason, fmt.Sprintf(format, a...))
    71  }
    72  
    73  func FromError(err error) *Error {
    74  	if err == nil {
    75  		return nil
    76  	}
    77  	if se := new(Error); errors.As(err, &se) {
    78  		return se
    79  	}
    80  	gs, ok := status.FromError(err)
    81  	if ok {
    82  		for _, detail := range gs.Details() {
    83  			switch d := detail.(type) {
    84  			case *errdetails.ErrorInfo:
    85  				return New(
    86  					httputil.StatusFromGRPCCode(gs.Code()),
    87  					d.Reason,
    88  					gs.Message(),
    89  				).AddMetadata(d.Metadata)
    90  			}
    91  		}
    92  	}
    93  	return New(UnknownCode, UnknownReason, err.Error())
    94  }
    95  
    96  // Code 返回err指定的错误码
    97  func Code(err error) int {
    98  	if err == nil {
    99  		return 0
   100  	}
   101  	if se := FromError(err); err != nil {
   102  		return int(se.Code)
   103  	}
   104  	return UnknownCode
   105  }
   106  
   107  // Reason 返回err的reason
   108  func Reason(err error) string {
   109  	if se := FromError(err); err != nil {
   110  		return se.Reason
   111  	}
   112  	return UnknownReason
   113  }
   114  
   115  func Is(err, target error) bool { return errors.Is(err, target) }
   116  
   117  func As(err error, target interface{}) bool { return errors.As(err, target) }
   118  
   119  func Unwrap(err error) error { return errors.Unwrap(err) }