1
0
mirror of https://github.com/go-kratos/kratos.git synced 2026-06-13 21:19:41 +02:00
Files

153 lines
3.5 KiB
Go
Raw Permalink Normal View History

2021-02-17 17:14:47 +08:00
package errors
import (
"errors"
"fmt"
2021-04-28 23:09:27 +08:00
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/status"
2022-09-27 14:08:08 +08:00
httpstatus "github.com/go-kratos/kratos/v2/transport/http/status"
2021-02-17 17:14:47 +08:00
)
2021-05-26 20:05:34 +08:00
const (
// UnknownCode is unknown code for error info.
UnknownCode = 500
// UnknownReason is unknown reason for error info.
UnknownReason = ""
2021-06-08 16:33:50 +08:00
// SupportPackageIsVersion1 this constant should not be referenced by any other code.
SupportPackageIsVersion1 = true
2021-05-26 20:05:34 +08:00
)
2021-05-25 15:01:53 +08:00
// Error is a status error.
type Error struct {
Status
cause error
}
2021-02-17 17:14:47 +08:00
2021-04-26 16:17:04 +08:00
func (e *Error) Error() string {
return fmt.Sprintf("error: code = %d reason = %s message = %s metadata = %v cause = %v", e.Code, e.Reason, e.Message, e.Metadata, e.cause)
2021-04-28 23:09:27 +08:00
}
// Unwrap provides compatibility for Go 1.13 error chains.
func (e *Error) Unwrap() error { return e.cause }
2021-02-17 17:14:47 +08:00
// Is matches each error in the chain with the target value.
2021-04-25 20:19:23 +08:00
func (e *Error) Is(err error) bool {
2021-05-25 00:56:31 +08:00
if se := new(Error); errors.As(err, &se) {
2022-03-01 12:04:57 +08:00
return se.Code == e.Code && se.Reason == e.Reason
2021-02-17 17:14:47 +08:00
}
return false
}
// WithCause with the underlying cause of the error.
func (e *Error) WithCause(cause error) *Error {
err := Clone(e)
err.cause = cause
return err
}
2021-04-28 23:09:27 +08:00
// WithMetadata with an MD formed by the mapping of key, value.
func (e *Error) WithMetadata(md map[string]string) *Error {
err := Clone(e)
2021-04-28 23:09:27 +08:00
err.Metadata = md
2021-05-25 00:56:31 +08:00
return err
2021-04-28 23:09:27 +08:00
}
// GRPCStatus returns the Status represented by se.
func (e *Error) GRPCStatus() *status.Status {
s, _ := status.New(httpstatus.ToGRPCCode(int(e.Code)), e.Message).
WithDetails(&errdetails.ErrorInfo{
Reason: e.Reason,
Metadata: e.Metadata,
})
return s
}
2021-04-26 16:17:04 +08:00
// New returns an error object for the code, message.
2021-05-25 15:01:53 +08:00
func New(code int, reason, message string) *Error {
2021-04-25 20:19:23 +08:00
return &Error{
Status: Status{
Code: int32(code),
Message: message,
Reason: reason,
},
2021-02-17 17:14:47 +08:00
}
}
2021-04-26 16:17:04 +08:00
// Newf New(code fmt.Sprintf(format, a...))
2025-03-07 18:56:30 +03:00
func Newf(code int, reason, format string, a ...any) *Error {
2021-05-25 15:01:53 +08:00
return New(code, reason, fmt.Sprintf(format, a...))
2021-04-26 16:17:04 +08:00
}
// Errorf returns an error object for the code, message and error info.
2025-03-07 18:56:30 +03:00
func Errorf(code int, reason, format string, a ...any) error {
2021-05-25 15:01:53 +08:00
return New(code, reason, fmt.Sprintf(format, a...))
2021-04-26 16:17:04 +08:00
}
2022-03-09 10:51:17 +08:00
// Code returns the http code for an error.
2021-04-25 20:19:23 +08:00
// It supports wrapped errors.
2021-05-26 20:05:34 +08:00
func Code(err error) int {
2021-02-17 17:14:47 +08:00
if err == nil {
return 200 //nolint:mnd
2021-02-17 17:14:47 +08:00
}
2022-01-01 23:01:24 +08:00
return int(FromError(err).Code)
2021-02-17 17:14:47 +08:00
}
2021-04-25 20:19:23 +08:00
// Reason returns the reason for a particular error.
2021-02-17 17:14:47 +08:00
// It supports wrapped errors.
func Reason(err error) string {
2022-01-01 23:01:24 +08:00
if err == nil {
return UnknownReason
2021-02-17 17:14:47 +08:00
}
2022-01-01 23:01:24 +08:00
return FromError(err).Reason
2021-02-17 17:14:47 +08:00
}
2021-04-29 10:56:53 +08:00
// Clone deep clone error to a new error.
func Clone(err *Error) *Error {
if err == nil {
return nil
}
metadata := make(map[string]string, len(err.Metadata))
for k, v := range err.Metadata {
metadata[k] = v
}
return &Error{
cause: err.cause,
Status: Status{
Code: err.Code,
Reason: err.Reason,
Message: err.Message,
Metadata: metadata,
},
}
}
2021-04-29 10:56:53 +08:00
// FromError try to convert an error to *Error.
// It supports wrapped errors.
func FromError(err error) *Error {
if err == nil {
return nil
}
2021-05-25 00:56:31 +08:00
if se := new(Error); errors.As(err, &se) {
return se
2021-04-29 10:56:53 +08:00
}
gs, ok := status.FromError(err)
2022-05-20 18:51:09 +08:00
if !ok {
return New(UnknownCode, UnknownReason, err.Error())
}
ret := New(
httpstatus.FromGRPCCode(gs.Code()),
UnknownReason,
gs.Message(),
)
for _, detail := range gs.Details() {
switch d := detail.(type) {
case *errdetails.ErrorInfo:
ret.Reason = d.Reason
return ret.WithMetadata(d.Metadata)
2021-04-29 10:56:53 +08:00
}
}
2022-05-20 18:51:09 +08:00
return ret
2021-04-29 10:56:53 +08:00
}