feature/error (#2)
Co-authored-by: daniel.w <daniel.w@intteam.net> Reviewed-on: #2
This commit is contained in:
parent
774db25eaa
commit
d72d324934
|
@ -0,0 +1,99 @@
|
||||||
|
package code
|
||||||
|
|
||||||
|
const (
|
||||||
|
OK uint32 = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scope
|
||||||
|
const (
|
||||||
|
Unset uint32 = iota
|
||||||
|
CloudEPPortalGW
|
||||||
|
CloudEPMember
|
||||||
|
CloudEPPermission
|
||||||
|
)
|
||||||
|
|
||||||
|
// Category for general operations: 100 - 4900
|
||||||
|
const (
|
||||||
|
_ = iota
|
||||||
|
CatInput uint32 = iota * 100
|
||||||
|
CatDB
|
||||||
|
CatResource
|
||||||
|
CatGRPC
|
||||||
|
CatAuth
|
||||||
|
CatSystem
|
||||||
|
CatPubSub
|
||||||
|
)
|
||||||
|
|
||||||
|
// CatArk Category for specific app/service: 5000 - 9900
|
||||||
|
const (
|
||||||
|
CatArk uint32 = (iota + 50) * 100
|
||||||
|
)
|
||||||
|
|
||||||
|
// Detail - Input 1xx
|
||||||
|
const (
|
||||||
|
_ = iota + CatInput
|
||||||
|
InvalidFormat
|
||||||
|
NotValidImplementation
|
||||||
|
InvalidRange
|
||||||
|
)
|
||||||
|
|
||||||
|
// Detail - Database 2xx
|
||||||
|
const (
|
||||||
|
_ = iota + CatDB
|
||||||
|
DBError // general error
|
||||||
|
DBDataConvert
|
||||||
|
DBDuplicate
|
||||||
|
)
|
||||||
|
|
||||||
|
// Detail - Resource 3xx
|
||||||
|
const (
|
||||||
|
_ = iota + CatResource
|
||||||
|
ResourceNotFound
|
||||||
|
InvalidResourceFormat
|
||||||
|
ResourceAlreadyExist
|
||||||
|
ResourceInsufficient
|
||||||
|
InsufficientPermission
|
||||||
|
InvalidMeasurementID
|
||||||
|
ResourceExpired
|
||||||
|
ResourceMigrated
|
||||||
|
InvalidResourceState
|
||||||
|
InsufficientQuota
|
||||||
|
ResourceHasMultiOwner
|
||||||
|
)
|
||||||
|
|
||||||
|
/* Detail - GRPC */
|
||||||
|
// The GRPC detail code uses Go GRPC's built-in codes.
|
||||||
|
// Refer to "google.golang.org/grpc/codes" for more detail.
|
||||||
|
|
||||||
|
// Detail - Auth 5xx
|
||||||
|
const (
|
||||||
|
_ = iota + CatAuth
|
||||||
|
Unauthorized
|
||||||
|
AuthExpired
|
||||||
|
InvalidPosixTime
|
||||||
|
SigAndPayloadNotMatched
|
||||||
|
Forbidden
|
||||||
|
)
|
||||||
|
|
||||||
|
// Detail - System 6xx
|
||||||
|
const (
|
||||||
|
_ = iota + CatSystem
|
||||||
|
SystemInternalError
|
||||||
|
SystemMaintainError
|
||||||
|
SystemTimeoutError
|
||||||
|
)
|
||||||
|
|
||||||
|
// Detail - PubSub 7xx
|
||||||
|
const (
|
||||||
|
_ = iota + CatPubSub
|
||||||
|
Publish
|
||||||
|
Consume
|
||||||
|
MsgSizeTooLarge
|
||||||
|
)
|
||||||
|
|
||||||
|
// Detail - Ark 5xxx
|
||||||
|
const (
|
||||||
|
_ = iota + CatArk
|
||||||
|
ArkInternal
|
||||||
|
ArkHttp400
|
||||||
|
)
|
|
@ -0,0 +1,13 @@
|
||||||
|
package code
|
||||||
|
|
||||||
|
// CatToStr collects general error messages for each Category
|
||||||
|
// It is used to send back to API caller
|
||||||
|
var CatToStr = map[uint32]string{
|
||||||
|
CatInput: "Invalid Input Data",
|
||||||
|
CatDB: "Database Error",
|
||||||
|
CatResource: "Resource Error",
|
||||||
|
CatGRPC: "Internal Service Communication Error",
|
||||||
|
CatAuth: "Authentication Error",
|
||||||
|
CatArk: "Internal Service Communication Error",
|
||||||
|
CatSystem: "System Error",
|
||||||
|
}
|
|
@ -0,0 +1,442 @@
|
||||||
|
package error
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.30cm.net/digimon/library-go/errors/code"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
_ "github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newErr(scope, detail uint32, msg string) *Err {
|
||||||
|
cat := detail / 100 * 100
|
||||||
|
return &Err{
|
||||||
|
category: cat,
|
||||||
|
code: detail,
|
||||||
|
scope: scope,
|
||||||
|
msg: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBuiltinGRPCErr(scope, detail uint32, msg string) *Err {
|
||||||
|
return &Err{
|
||||||
|
category: code.CatGRPC,
|
||||||
|
code: detail,
|
||||||
|
scope: scope,
|
||||||
|
msg: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromError tries to let error as Err
|
||||||
|
// it supports to unwrap error that has Err
|
||||||
|
// return nil if failed to transfer
|
||||||
|
func FromError(err error) *Err {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var e *Err
|
||||||
|
if errors.As(err, &e) {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromCode parses code as following
|
||||||
|
// Decimal: 120314
|
||||||
|
// 12 represents Scope
|
||||||
|
// 03 represents Category
|
||||||
|
// 14 represents Detail error code
|
||||||
|
func FromCode(code uint32) *Err {
|
||||||
|
scope := code / 10000
|
||||||
|
detail := code % 10000
|
||||||
|
return &Err{
|
||||||
|
category: detail / 100 * 100,
|
||||||
|
code: detail,
|
||||||
|
scope: scope,
|
||||||
|
msg: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromGRPCError transfer error to Err
|
||||||
|
// useful for gRPC client
|
||||||
|
func FromGRPCError(err error) *Err {
|
||||||
|
s, _ := status.FromError(err)
|
||||||
|
e := FromCode(uint32(s.Code()))
|
||||||
|
e.msg = s.Message()
|
||||||
|
|
||||||
|
// For GRPC built-in code
|
||||||
|
if e.Scope() == code.Unset && e.Category() == 0 && e.Code() != code.OK {
|
||||||
|
e = newBuiltinGRPCErr(Scope, e.Code(), s.Message())
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: check GRPCStatus() in Errs struct
|
||||||
|
// ToGRPCError returns the status.Status
|
||||||
|
// Useful to return error in gRPC server
|
||||||
|
func ToGRPCError(e *Err) error {
|
||||||
|
return status.New(codes.Code(e.FullCode()), e.Error()).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** System ***/
|
||||||
|
|
||||||
|
// SystemTimeoutError returns Err
|
||||||
|
func SystemTimeoutError(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.SystemTimeoutError, fmt.Sprintf("system timeout: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemTimeoutErrorL logs error message and returns Err
|
||||||
|
func SystemTimeoutErrorL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := SystemTimeoutError(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemInternalError returns Err struct
|
||||||
|
func SystemInternalError(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.SystemInternalError, fmt.Sprintf("internal error: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemInternalErrorL logs error message and returns Err
|
||||||
|
func SystemInternalErrorL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := SystemInternalError(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemMaintainErrorL logs error message and returns Err
|
||||||
|
func SystemMaintainErrorL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := SystemMaintainError(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemMaintainError returns Err struct
|
||||||
|
func SystemMaintainError(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.SystemMaintainError, fmt.Sprintf("service under maintenance: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** CatInput ***/
|
||||||
|
|
||||||
|
// InvalidFormat returns Err struct
|
||||||
|
func InvalidFormat(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.InvalidFormat, fmt.Sprintf("invalid format: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidFormatL logs error message and returns Err
|
||||||
|
func InvalidFormatL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := InvalidFormat(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidRange returns Err struct
|
||||||
|
func InvalidRange(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.InvalidRange, fmt.Sprintf("invalid range: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidRangeL logs error message and returns Err
|
||||||
|
func InvalidRangeL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := InvalidRange(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotValidImplementation returns Err struct
|
||||||
|
func NotValidImplementation(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.NotValidImplementation, fmt.Sprintf("not valid implementation: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotValidImplementationL logs error message and returns Err
|
||||||
|
func NotValidImplementationL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := NotValidImplementation(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** CatDB ***/
|
||||||
|
|
||||||
|
// DBError returns Err
|
||||||
|
func DBError(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.DBError, fmt.Sprintf("db error: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBErrorL logs error message and returns Err
|
||||||
|
func DBErrorL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := DBError(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBDataConvert returns Err
|
||||||
|
func DBDataConvert(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.DBDataConvert, fmt.Sprintf("data from db convert error: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBDataConvertL logs error message and returns Err
|
||||||
|
func DBDataConvertL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := DBDataConvert(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBDuplicate returns Err
|
||||||
|
func DBDuplicate(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.DBDuplicate, fmt.Sprintf("data Duplicate key error: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBDuplicateL logs error message and returns Err
|
||||||
|
func DBDuplicateL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := DBDuplicate(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** CatResource ***/
|
||||||
|
|
||||||
|
// ResourceNotFound returns Err and logging
|
||||||
|
func ResourceNotFound(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.ResourceNotFound, fmt.Sprintf("resource not found: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceNotFoundL logs error message and returns Err
|
||||||
|
func ResourceNotFoundL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := ResourceNotFound(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidResourceFormat returns Err
|
||||||
|
func InvalidResourceFormat(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.InvalidResourceFormat, fmt.Sprintf("invalid resource format: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidResourceFormatL logs error message and returns Err
|
||||||
|
func InvalidResourceFormatL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := InvalidResourceFormat(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidResourceState returns status not correct.
|
||||||
|
// for example: company should be destroy, agent should be no-sensor/fail-install ...
|
||||||
|
func InvalidResourceState(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.InvalidResourceState, fmt.Sprintf("invalid resource state: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidResourceStateL logs error message and returns status not correct.
|
||||||
|
func InvalidResourceStateL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := InvalidResourceState(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResourceInsufficient(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.ResourceInsufficient,
|
||||||
|
fmt.Sprintf("insufficient resource: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResourceInsufficientL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := ResourceInsufficient(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsufficientPermission returns Err
|
||||||
|
func InsufficientPermission(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.InsufficientPermission,
|
||||||
|
fmt.Sprintf("insufficient permission: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsufficientPermissionL returns Err and log
|
||||||
|
func InsufficientPermissionL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := InsufficientPermission(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceAlreadyExist returns Err
|
||||||
|
func ResourceAlreadyExist(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.ResourceAlreadyExist, fmt.Sprintf("resource already exist: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceAlreadyExistL logs error message and returns Err
|
||||||
|
func ResourceAlreadyExistL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := ResourceAlreadyExist(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidMeasurementID returns Err
|
||||||
|
func InvalidMeasurementID(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.InvalidMeasurementID, fmt.Sprintf("missing measurement id: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidMeasurementIDL logs error message and returns Err
|
||||||
|
func InvalidMeasurementIDL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := InvalidMeasurementID(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceExpired returns Err
|
||||||
|
func ResourceExpired(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.ResourceExpired, fmt.Sprintf("resource expired: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceExpiredL logs error message and returns Err
|
||||||
|
func ResourceExpiredL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := ResourceExpired(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceMigrated returns Err
|
||||||
|
func ResourceMigrated(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.ResourceMigrated, fmt.Sprintf("resource migrated: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceMigratedL logs error message and returns Err
|
||||||
|
func ResourceMigratedL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := ResourceMigrated(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsufficientQuota returns Err
|
||||||
|
func InsufficientQuota(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.InsufficientQuota, fmt.Sprintf("insufficient quota: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsufficientQuotaL logs error message and returns Err
|
||||||
|
func InsufficientQuotaL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := InsufficientQuota(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** CatAuth ***/
|
||||||
|
|
||||||
|
// Unauthorized returns Err
|
||||||
|
func Unauthorized(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.Unauthorized, fmt.Sprintf("unauthorized: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnauthorizedL logs error message and returns Err
|
||||||
|
func UnauthorizedL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := Unauthorized(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthExpired returns Err
|
||||||
|
func AuthExpired(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.AuthExpired, fmt.Sprintf("expired: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthExpiredL logs error message and returns Err
|
||||||
|
func AuthExpiredL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := AuthExpired(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidPosixTime returns Err
|
||||||
|
func InvalidPosixTime(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.InvalidPosixTime, fmt.Sprintf("invalid posix time: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidPosixTimeL logs error message and returns Err
|
||||||
|
func InvalidPosixTimeL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := InvalidPosixTime(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// SigAndPayloadNotMatched returns Err
|
||||||
|
func SigAndPayloadNotMatched(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.SigAndPayloadNotMatched, fmt.Sprintf("signature and the payload are not match: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SigAndPayloadNotMatchedL logs error message and returns Err
|
||||||
|
func SigAndPayloadNotMatchedL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := SigAndPayloadNotMatched(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forbidden returns Err
|
||||||
|
func Forbidden(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.Forbidden, fmt.Sprintf("forbidden: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForbiddenL logs error message and returns Err
|
||||||
|
func ForbiddenL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := Forbidden(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAuthUnauthorizedError check the err is unauthorized error
|
||||||
|
func IsAuthUnauthorizedError(err *Err) bool {
|
||||||
|
switch err.Code() {
|
||||||
|
case code.Unauthorized, code.AuthExpired, code.InvalidPosixTime,
|
||||||
|
code.SigAndPayloadNotMatched, code.Forbidden,
|
||||||
|
code.InvalidFormat, code.ResourceNotFound:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** CatXBC ***/
|
||||||
|
|
||||||
|
// ArkInternal returns Err
|
||||||
|
func ArkInternal(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.ArkInternal, fmt.Sprintf("ark internal error: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArkInternalL logs error message and returns Err
|
||||||
|
func ArkInternalL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := ArkInternal(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** CatPubSub ***/
|
||||||
|
|
||||||
|
// Publish returns Err
|
||||||
|
func Publish(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.Publish, fmt.Sprintf("publish: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublishL logs error message and returns Err
|
||||||
|
func PublishL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := Publish(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume returns Err
|
||||||
|
func Consume(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.Consume, fmt.Sprintf("consume: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgSizeTooLarge returns Err
|
||||||
|
func MsgSizeTooLarge(s ...string) *Err {
|
||||||
|
return newErr(Scope, code.MsgSizeTooLarge, fmt.Sprintf("kafka error: %s", strings.Join(s, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgSizeTooLargeL logs error message and returns Err
|
||||||
|
func MsgSizeTooLargeL(l logx.Logger, s ...string) *Err {
|
||||||
|
e := MsgSizeTooLarge(s...)
|
||||||
|
l.WithCallerSkip(1).Error(e.Error())
|
||||||
|
return e
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,218 @@
|
||||||
|
package error
|
||||||
|
|
||||||
|
import (
|
||||||
|
code2 "code.30cm.net/digimon/library-go/errors/code"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scope 全域變數應由服務或模組設置
|
||||||
|
var Scope = code2.Unset
|
||||||
|
|
||||||
|
// Err 6 碼,服務 2, 大類 2, 詳細錯誤 2
|
||||||
|
type Err struct {
|
||||||
|
category uint32
|
||||||
|
code uint32
|
||||||
|
scope uint32
|
||||||
|
msg string
|
||||||
|
internalErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error 是錯誤的介面
|
||||||
|
// 私有屬性 "msg" 的 getter 函數
|
||||||
|
func (e *Err) Error() string {
|
||||||
|
if e == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 internal err 存在,連接錯誤字串
|
||||||
|
var internalErrStr string
|
||||||
|
if e.internalErr != nil {
|
||||||
|
internalErrStr = e.internalErr.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.msg != "" {
|
||||||
|
if internalErrStr != "" {
|
||||||
|
return fmt.Sprintf("%s: %s", e.msg, internalErrStr)
|
||||||
|
}
|
||||||
|
return e.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
generalErrStr := e.GeneralError()
|
||||||
|
if internalErrStr != "" {
|
||||||
|
return fmt.Sprintf("%s: %s", generalErrStr, internalErrStr)
|
||||||
|
}
|
||||||
|
return generalErrStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Category 私有屬性 "category" 的 getter 函數
|
||||||
|
func (e *Err) Category() uint32 {
|
||||||
|
if e == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return e.category
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scope 私有屬性 "scope" 的 getter 函數
|
||||||
|
func (e *Err) Scope() uint32 {
|
||||||
|
if e == nil {
|
||||||
|
return code2.Unset
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.scope
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeStr 返回帶有零填充的錯誤代碼字串
|
||||||
|
func (e *Err) CodeStr() string {
|
||||||
|
if e == nil {
|
||||||
|
return "00000"
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Category() == code2.CatGRPC {
|
||||||
|
return fmt.Sprintf("%d%04d", e.Scope(), e.Category()+e.Code())
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%d%04d", e.Scope(), e.Code())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code 私有屬性 "code" 的 getter 函數
|
||||||
|
func (e *Err) Code() uint32 {
|
||||||
|
if e == nil {
|
||||||
|
return code2.OK
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Err) FullCode() uint32 {
|
||||||
|
if e == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Category() == code2.CatGRPC {
|
||||||
|
return e.Scope()*10000 + e.Category() + e.Code()
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.Scope()*10000 + e.Code()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPStatus 返回對應的 HTTP 狀態碼
|
||||||
|
func (e *Err) HTTPStatus() int {
|
||||||
|
if e == nil || e.Code() == code2.OK {
|
||||||
|
return http.StatusOK
|
||||||
|
}
|
||||||
|
// 根據 code 判斷狀態碼
|
||||||
|
switch e.Code() {
|
||||||
|
case code2.ResourceInsufficient:
|
||||||
|
// 400
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case code2.Unauthorized, code2.InsufficientPermission:
|
||||||
|
// 401
|
||||||
|
return http.StatusUnauthorized
|
||||||
|
case code2.InsufficientQuota:
|
||||||
|
// 402
|
||||||
|
return http.StatusPaymentRequired
|
||||||
|
case code2.InvalidPosixTime, code2.Forbidden:
|
||||||
|
// 403
|
||||||
|
return http.StatusForbidden
|
||||||
|
case code2.ResourceNotFound:
|
||||||
|
// 404
|
||||||
|
return http.StatusNotFound
|
||||||
|
case code2.ResourceAlreadyExist, code2.InvalidResourceState:
|
||||||
|
// 409
|
||||||
|
return http.StatusConflict
|
||||||
|
case code2.NotValidImplementation:
|
||||||
|
// 501
|
||||||
|
return http.StatusNotImplemented
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據 category 判斷狀態碼
|
||||||
|
switch e.Category() {
|
||||||
|
case code2.CatInput:
|
||||||
|
return http.StatusBadRequest
|
||||||
|
default:
|
||||||
|
// 如果沒有符合的條件,返回狀態碼 500
|
||||||
|
return http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneralError 轉換 category 級別錯誤訊息
|
||||||
|
// 這是給客戶或 API 調用者的一般錯誤訊息
|
||||||
|
func (e *Err) GeneralError() string {
|
||||||
|
if e == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
errStr, ok := code2.CatToStr[e.Category()]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return errStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is 在執行 errors.Is() 時調用。
|
||||||
|
// 除非你非常確定你在做什麼,否則不要直接使用這個函數。
|
||||||
|
// 請使用 errors.Is 代替。
|
||||||
|
// 此函數比較兩個錯誤變量是否都是 *Err,並且具有相同的 code(不檢查包裹的內部錯誤)
|
||||||
|
func (e *Err) Is(f error) bool {
|
||||||
|
var err *Err
|
||||||
|
ok := errors.As(f, &err)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return e.Code() == err.Code()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap 返回底層錯誤
|
||||||
|
// 解除包裹錯誤的結果本身可能具有 Unwrap 方法;
|
||||||
|
// 我們稱通過反覆解除包裹產生的錯誤序列為錯誤鏈。
|
||||||
|
func (e *Err) Unwrap() error {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e.internalErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap 將內部錯誤設置到 Err 結構
|
||||||
|
func (e *Err) Wrap(internalErr error) *Err {
|
||||||
|
if e != nil {
|
||||||
|
e.internalErr = internalErr
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Err) GRPCStatus() *status.Status {
|
||||||
|
if e == nil {
|
||||||
|
return status.New(codes.OK, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return status.New(codes.Code(e.FullCode()), e.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工廠函數
|
||||||
|
|
||||||
|
// NewErr 創建新的 Err
|
||||||
|
func NewErr(scope, category, detail uint32, msg string) *Err {
|
||||||
|
return &Err{
|
||||||
|
category: category,
|
||||||
|
code: detail,
|
||||||
|
scope: scope,
|
||||||
|
msg: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGRPCErr 創建新的 gRPC Err
|
||||||
|
func NewGRPCErr(scope, detail uint32, msg string) *Err {
|
||||||
|
return &Err{
|
||||||
|
category: code2.CatGRPC,
|
||||||
|
code: detail,
|
||||||
|
scope: scope,
|
||||||
|
msg: msg,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,297 @@
|
||||||
|
package error
|
||||||
|
|
||||||
|
import (
|
||||||
|
code2 "code.30cm.net/digimon/library-go/errors/code"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
var e *Err = nil
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
assert.Equal(t, code2.OK, e.Code())
|
||||||
|
assert.Equal(t, "00000", e.CodeStr())
|
||||||
|
assert.Equal(t, "", e.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCode_GivenScope99DetailCode6687_ShouldReturn996687(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := Err{scope: 99, code: 6687}
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
assert.Equal(t, uint32(6687), e.Code())
|
||||||
|
assert.Equal(t, "996687", e.CodeStr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCode_GivenScope0DetailCode87_ShouldReturn87(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := Err{scope: 0, code: 87}
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
assert.Equal(t, uint32(87), e.Code())
|
||||||
|
assert.Equal(t, "00087", e.CodeStr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromCode_Given870005_ShouldHasScope87_Cat0_Detail5(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := FromCode(870005)
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.Equal(t, uint32(87), e.Scope())
|
||||||
|
assert.Equal(t, uint32(0), e.Category())
|
||||||
|
assert.Equal(t, uint32(5), e.Code())
|
||||||
|
assert.Equal(t, "", e.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromCode_Given0_ShouldHasScope0_Cat0_Detail0(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := FromCode(0)
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.Equal(t, uint32(0), e.Scope())
|
||||||
|
assert.Equal(t, uint32(0), e.Category())
|
||||||
|
assert.Equal(t, uint32(0), e.Code())
|
||||||
|
assert.Equal(t, "", e.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromCode_Given9105_ShouldHasScope0_Cat9100_Detail9105(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := FromCode(9105)
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.Equal(t, uint32(0), e.Scope())
|
||||||
|
assert.Equal(t, uint32(9100), e.Category())
|
||||||
|
assert.Equal(t, uint32(9105), e.Code())
|
||||||
|
assert.Equal(t, "", e.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErr_ShouldImplementErrorFunction(t *testing.T) {
|
||||||
|
// setup a func return error
|
||||||
|
f := func() error { return InvalidFormat("fake field") }
|
||||||
|
|
||||||
|
// act
|
||||||
|
err := f()
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Contains(t, fmt.Sprint(err), "fake field") // can be printed
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeneralError_GivenNilErr_ShouldReturnEmptyString(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
var e *Err = nil
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
assert.Equal(t, "", e.GeneralError())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeneralError_GivenNotExistCat_ShouldReturnEmptyString(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := Err{category: 123456}
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
assert.Equal(t, "", e.GeneralError())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := Err{category: code2.CatDB}
|
||||||
|
catErrStr := code2.CatToStr[code2.CatDB]
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
assert.Equal(t, catErrStr, e.GeneralError())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestError_GivenEmptyMsg_ShouldReturnCatGeneralErrorMessage(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := Err{category: code2.CatDB, msg: ""}
|
||||||
|
|
||||||
|
// act
|
||||||
|
errMsg := e.Error()
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.Equal(t, code2.CatToStr[code2.CatDB], errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestError_GivenMsg_ShouldReturnGiveMsg(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
e := Err{msg: "FAKE"}
|
||||||
|
|
||||||
|
// act
|
||||||
|
errMsg := e.Error()
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.Equal(t, "FAKE", errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
||||||
|
var nilErrs *Err
|
||||||
|
// act
|
||||||
|
result := errors.Is(nilErrs, DBError())
|
||||||
|
result2 := errors.Is(DBError(), nilErrs)
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.False(t, result)
|
||||||
|
assert.False(t, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIs_GivenNil_ShouldReturnFalse(t *testing.T) {
|
||||||
|
// act
|
||||||
|
result := errors.Is(nil, DBError())
|
||||||
|
result2 := errors.Is(DBError(), nil)
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.False(t, result)
|
||||||
|
assert.False(t, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIs_GivenNilReceiver_ShouldReturnCorrectResult(t *testing.T) {
|
||||||
|
var nilErr *Err = nil
|
||||||
|
|
||||||
|
// test 1: nilErr != DBError
|
||||||
|
var dbErr error = DBError("fake db error")
|
||||||
|
assert.False(t, nilErr.Is(dbErr))
|
||||||
|
|
||||||
|
// test 2: nilErr != nil error
|
||||||
|
var nilError error
|
||||||
|
assert.False(t, nilErr.Is(nilError))
|
||||||
|
|
||||||
|
// test 3: nilErr == another nilErr
|
||||||
|
var nilErr2 *Err = nil
|
||||||
|
assert.True(t, nilErr.Is(nilErr2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIs_GivenDBError_ShouldReturnTrue(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
dbErr := DBError("fake db error")
|
||||||
|
|
||||||
|
// act
|
||||||
|
result := errors.Is(dbErr, DBError("not care"))
|
||||||
|
result2 := errors.Is(DBError(), dbErr)
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.True(t, result)
|
||||||
|
assert.True(t, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIs_GivenDBErrorAssignToErrorType_ShouldReturnTrue(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
var dbErr error = DBError("fake db error")
|
||||||
|
|
||||||
|
// act
|
||||||
|
result := errors.Is(dbErr, DBError("not care"))
|
||||||
|
result2 := errors.Is(DBError(), dbErr)
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.True(t, result)
|
||||||
|
assert.True(t, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrap_GivenNilErr_ShouldNoPanic(t *testing.T) {
|
||||||
|
// act & assert
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
var e *Err = nil
|
||||||
|
_ = e.Wrap(fmt.Errorf("test"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrap_GivenErrorToWrap_ShouldReturnErrorWithWrappedError(t *testing.T) {
|
||||||
|
// act & assert
|
||||||
|
wrappedErr := fmt.Errorf("test")
|
||||||
|
wrappingErr := SystemInternalError("WrappingError").Wrap(wrappedErr)
|
||||||
|
unWrappedErr := wrappingErr.Unwrap()
|
||||||
|
|
||||||
|
assert.Equal(t, wrappedErr, unWrappedErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnwrap_GivenNilErr_ShouldReturnNil(t *testing.T) {
|
||||||
|
var e *Err = nil
|
||||||
|
internalErr := e.Unwrap()
|
||||||
|
assert.Nil(t, internalErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorsIs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
||||||
|
var e *Err = nil
|
||||||
|
assert.False(t, errors.Is(e, fmt.Errorf("test")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorsAs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
||||||
|
var internalErr *testErr
|
||||||
|
var e *Err = nil
|
||||||
|
assert.False(t, errors.As(e, &internalErr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGRPCStatus(t *testing.T) {
|
||||||
|
// setup table driven tests
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
given *Err
|
||||||
|
expect *status.Status
|
||||||
|
expectConvert error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"nil errs.Err",
|
||||||
|
nil,
|
||||||
|
status.New(codes.OK, ""),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"InvalidFormat Err",
|
||||||
|
InvalidFormat("fake"),
|
||||||
|
status.New(codes.Code(101), "invalid format: fake"),
|
||||||
|
status.New(codes.Code(101), "invalid format: fake").Err(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
s := test.given.GRPCStatus()
|
||||||
|
assert.Equal(t, test.expect.Code(), s.Code())
|
||||||
|
assert.Equal(t, test.expect.Message(), s.Message())
|
||||||
|
assert.Equal(t, test.expectConvert, status.Convert(test.given).Err())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErr_HTTPStatus(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
err *Err
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
{name: "nil error", err: nil, want: http.StatusOK},
|
||||||
|
{name: "invalid measurement id", err: &Err{category: code2.CatResource, code: code2.InvalidMeasurementID}, want: http.StatusInternalServerError},
|
||||||
|
{name: "resource already exists", err: &Err{category: code2.CatResource, code: code2.ResourceAlreadyExist}, want: http.StatusConflict},
|
||||||
|
{name: "invalid resource state", err: &Err{category: code2.CatResource, code: code2.InvalidResourceState}, want: http.StatusConflict},
|
||||||
|
{name: "invalid posix time", err: &Err{category: code2.CatAuth, code: code2.InvalidPosixTime}, want: http.StatusForbidden},
|
||||||
|
{name: "unauthorized", err: &Err{category: code2.CatAuth, code: code2.Unauthorized}, want: http.StatusUnauthorized},
|
||||||
|
{name: "db error", err: &Err{category: code2.CatDB, code: code2.DBError}, want: http.StatusInternalServerError},
|
||||||
|
{name: "insufficient permission", err: &Err{category: code2.CatResource, code: code2.InsufficientPermission}, want: http.StatusUnauthorized},
|
||||||
|
{name: "resource insufficient", err: &Err{category: code2.CatResource, code: code2.ResourceInsufficient}, want: http.StatusBadRequest},
|
||||||
|
{name: "invalid format", err: &Err{category: code2.CatInput, code: code2.InvalidFormat}, want: http.StatusBadRequest},
|
||||||
|
{name: "resource not found", err: &Err{code: code2.ResourceNotFound}, want: http.StatusNotFound},
|
||||||
|
{name: "ok", err: &Err{code: code2.OK}, want: http.StatusOK},
|
||||||
|
{name: "not valid implementation", err: &Err{category: code2.CatInput, code: code2.NotValidImplementation}, want: http.StatusNotImplemented},
|
||||||
|
{name: "forbidden", err: &Err{category: code2.CatAuth, code: code2.Forbidden}, want: http.StatusForbidden},
|
||||||
|
{name: "insufficient quota", err: &Err{category: code2.CatResource, code: code2.InsufficientQuota}, want: http.StatusPaymentRequired},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
||||||
|
// act
|
||||||
|
got := tt.err.HTTPStatus()
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
module code.30cm.net/digimon/library-go/errors
|
||||||
|
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/zeromicro/go-zero v1.7.0
|
||||||
|
google.golang.org/grpc v1.65.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/fatih/color v1.17.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||||
|
go.uber.org/automaxprocs v1.5.3 // indirect
|
||||||
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
|
||||||
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,125 @@
|
||||||
|
## Purpose of errs package
|
||||||
|
1. compatible with `error` interface
|
||||||
|
2. encapsulate error message with functions in `easy_function.go`
|
||||||
|
3. easy for gRPC client/server
|
||||||
|
4. support err's chain by [Working with Errors in Go 1.13](https://blog.golang.org/go1.13-errors)
|
||||||
|
|
||||||
|
|
||||||
|
## Example - Normal function
|
||||||
|
Using builtin functions `InvalidInput` to generate `Err struct`
|
||||||
|
|
||||||
|
**please add your own functions if not exist**
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "adc.github.trendmicro.com/commercial-mgcp/library-go/pkg/errs"
|
||||||
|
|
||||||
|
func handleParam(s string) error {
|
||||||
|
// check user_id format
|
||||||
|
if ok := userIDFormat(s); !ok {
|
||||||
|
return errs.InvalidFormat("param user_id")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example - gRPC Server
|
||||||
|
`GetAgent` is a method of gRPC server, it wraps `Err` struct to `status.Status` struct
|
||||||
|
```go
|
||||||
|
func (as *agentService) GetAgent(ctx context.Context, req *cloudep.GetAgentRequest) (*cloudep.GetAgentResponse, error) {
|
||||||
|
l := log.WithFields(logger.Fields{"tenant_id": req.TenantId, "agent_id": req.AgentId, "method": "GetAgent"})
|
||||||
|
|
||||||
|
tenantID, err := primitive.ObjectIDFromHex(req.TenantId)
|
||||||
|
if err != nil {
|
||||||
|
// err maybe errs.Err or general error
|
||||||
|
// it's safe to use Convert() here
|
||||||
|
return nil, status.Convert(err).Err()
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Example - gRPC Client
|
||||||
|
Calling `GetAgent` and retry when Category is "DB"
|
||||||
|
```go
|
||||||
|
client := cloudep.NewAgentServiceClient(conn)
|
||||||
|
req := cloudep.GetAgentRequest{
|
||||||
|
TenantId: "not-a-valid-object-id",
|
||||||
|
AgentId: "5eb4fa99006d53c0cb6f9cfe",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry if DB error
|
||||||
|
for retry := 3; retry > 0 ; retry-- {
|
||||||
|
resp, err := client.GetAgent(context.Background(), &req)
|
||||||
|
if err != nil {
|
||||||
|
e := errs.FromGRPCError(err)
|
||||||
|
if e.Category() == code.CatGRPC {
|
||||||
|
if e.Code() == uint32(codes.Unavailable) {
|
||||||
|
log.warn("GRPC service unavailable. Retrying...")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.errorf("GRPC built-in error: %v", e)
|
||||||
|
}
|
||||||
|
if e.Category() == code.CatDB {
|
||||||
|
log.warn("retry...")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example - REST server
|
||||||
|
1. handling gRPC client error
|
||||||
|
2. transfer to HTTP code
|
||||||
|
3. transfer to Error body
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Handler(c *gin.Context) {
|
||||||
|
|
||||||
|
// handle error from gRPC client
|
||||||
|
resp, err := client.GetAgent(context.Background(), &req)
|
||||||
|
if err != nil {
|
||||||
|
// to Err
|
||||||
|
e := errs.FromGRPCError(err)
|
||||||
|
|
||||||
|
// get HTTP code & response struct
|
||||||
|
// 2nd parameter true means return general error message to user
|
||||||
|
c.JSON(e.HTTPStatus(), general.NewError(e, true))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example - Error Chain
|
||||||
|
1. set internal error by func `Wrap`
|
||||||
|
2. check Err has any error in err's chain matches the target by `errors.Is`
|
||||||
|
3. finds the first error in err's chain that matches target by `errors.As`
|
||||||
|
|
||||||
|
```go
|
||||||
|
// define a specific err type
|
||||||
|
type testErr struct {
|
||||||
|
code int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testErr) Error() string {
|
||||||
|
return strconv.Itoa(e.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
layer1Err := &testErr{code: 123}
|
||||||
|
// error chain: InvalidFormat -> layer 1 err
|
||||||
|
layer2Err := InvalidFormat("field A", "")
|
||||||
|
layer2Err.Wrap(layer1Err) //set internal error
|
||||||
|
|
||||||
|
// errors.Is should report true
|
||||||
|
hasLayer1Err := errors.Is(layer2Err, layer1Err)
|
||||||
|
|
||||||
|
// errors.As should return internal error
|
||||||
|
var internalErr *testErr
|
||||||
|
ok := errors.As(layer2Err, &internalErr)
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,198 @@
|
||||||
|
cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w=
|
||||||
|
cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
|
||||||
|
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||||
|
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
|
||||||
|
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
||||||
|
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
|
||||||
|
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||||
|
github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA=
|
||||||
|
github.com/alicebob/miniredis/v2 v2.33.0/go.mod h1:MhP4a3EU7aENRi9aO+tHfTBZicLqQevyi/DJpoj6mi0=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM=
|
||||||
|
github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||||
|
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||||
|
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
||||||
|
github.com/fullstorydev/grpcurl v1.9.1 h1:YxX1aCcCc4SDBQfj9uoWcTLe8t4NWrZe1y+mk83BQgo=
|
||||||
|
github.com/fullstorydev/grpcurl v1.9.1/go.mod h1:i8gKLIC6s93WdU3LSmkE5vtsCxyRmihUj5FK1cNW5EM=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
|
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||||
|
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
|
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
|
||||||
|
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||||
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||||
|
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||||
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||||
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||||
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
|
||||||
|
github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
|
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||||
|
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
|
github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
|
||||||
|
github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||||
|
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||||
|
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||||
|
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||||
|
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||||
|
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||||
|
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||||
|
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||||
|
github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
|
||||||
|
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
|
||||||
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
|
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||||
|
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
|
||||||
|
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
||||||
|
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||||
|
go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk=
|
||||||
|
go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM=
|
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA=
|
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU=
|
||||||
|
go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4=
|
||||||
|
go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU=
|
||||||
|
go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4BQ4=
|
||||||
|
go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
|
||||||
|
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
|
||||||
|
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA=
|
||||||
|
go.opentelemetry.io/otel/exporters/zipkin v1.24.0 h1:3evrL5poBuh1KF51D9gO/S+N/1msnm4DaBqs/rpXUqY=
|
||||||
|
go.opentelemetry.io/otel/exporters/zipkin v1.24.0/go.mod h1:0EHgD8R0+8yRhUYJOGR8Hfg2dpiJQxDOszd5smVO9wM=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||||
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||||
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||||
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
|
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||||
|
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||||
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
|
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
|
||||||
|
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||||
|
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||||
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
|
||||||
|
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
|
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
|
||||||
|
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
|
||||||
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw=
|
||||||
|
k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80=
|
||||||
|
k8s.io/apimachinery v0.29.4 h1:RaFdJiDmuKs/8cm1M6Dh1Kvyh59YQFDcFuFTSmXes6Q=
|
||||||
|
k8s.io/apimachinery v0.29.4/go.mod h1:i3FJVwhvSp/6n8Fl4K97PJEP8C+MM+aoDq4+ZJBf70Y=
|
||||||
|
k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg=
|
||||||
|
k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0=
|
||||||
|
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
|
||||||
|
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
|
||||||
|
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
|
||||||
|
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
||||||
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
Loading…
Reference in New Issue