package lib import ( "errors" "fmt" "go.uber.org/zap/zapcore" "runtime" ) type code uint8 const ( ErrValidationFailed code = 1 ErrInternal code = 2 ErrExternal code = 3 ErrNoPermission code = 4 ErrUnknown code = 5 ErrDeadlineExceeded code = 6 ErrNotFound code = 7 ErrAlreadyExists code = 8 ErrConflict code = 9 ErrUnimplemented code = 10 ErrBadInput code = 11 ErrUnauthenticated code = 12 ) func (c code) String() string { switch { case errors.Is(c, ErrValidationFailed): return "validation error" case errors.Is(c, ErrInternal): return "internal error" case errors.Is(c, ErrExternal): return "external error" case errors.Is(c, ErrNoPermission): return "permission error" case errors.Is(c, ErrUnknown): return "unknown error" case errors.Is(c, ErrDeadlineExceeded): return "deadline error" case errors.Is(c, ErrNotFound): return "not found error" case errors.Is(c, ErrAlreadyExists): return "already exists error" case errors.Is(c, ErrConflict): return "conflict error" case errors.Is(c, ErrUnimplemented): return "unimplemented error" case errors.Is(c, ErrBadInput): return "bad input error" } panic("unimplemented") } func (c code) Error() string { return c.String() } type layer uint8 const ( LayerTransport layer = 1 LayerService layer = 2 LayerStorage layer = 3 ) func (l layer) String() string { switch l { case LayerTransport: return "transport" case LayerService: return "service" case LayerStorage: return "storage" } panic("unimplemented") } func location(skip int) string { _, file, line, _ := runtime.Caller(skip) return fmt.Sprintf("%s:%d", file, line) } type Error struct { src error layer layer code code msg string loc string } func wrap(src error, layer layer, class code, msg string, loc string) *Error { return &Error{ src: src, layer: layer, code: class, msg: msg, loc: loc, } } func (e *Error) Unwrap() []error { return []error{e.src, e.code} } func (e *Error) Error() string { return fmt.Sprintf("%s: %s", e.code.String(), e.msg) } func (e *Error) MarshalLogObject(encoder zapcore.ObjectEncoder) error { if e.src != nil { encoder.AddString("src", e.src.Error()) } encoder.AddString("layer", e.layer.String()) encoder.AddString("code", e.code.String()) encoder.AddString("msg", e.msg) return nil } func TransportError(src error, code code, msg string) error { return wrap(src, LayerTransport, code, msg, location(2)) } func ServiceError(src error, code code, msg string) error { return wrap(src, LayerService, code, msg, location(2)) } func StorageError(src error, code code, msg string) error { return wrap(src, LayerStorage, code, msg, location(2)) }