164 lines
5.2 KiB
Go
164 lines
5.2 KiB
Go
package errutil
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/cockroachdb/errors/errbase"
|
|
"github.com/cockroachdb/errors/errorspb"
|
|
"github.com/cockroachdb/redact"
|
|
"github.com/gogo/protobuf/proto"
|
|
)
|
|
|
|
// leafError is like the basic error string in the stdlib except the
|
|
// message can contain redactable and non-redactable parts.
|
|
type leafError struct {
|
|
msg redact.RedactableString
|
|
}
|
|
|
|
var _ error = (*leafError)(nil)
|
|
var _ fmt.Formatter = (*leafError)(nil)
|
|
var _ errbase.SafeFormatter = (*leafError)(nil)
|
|
var _ errbase.SafeDetailer = (*leafError)(nil)
|
|
|
|
func (l *leafError) Error() string { return l.msg.StripMarkers() }
|
|
func (l *leafError) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) }
|
|
func (l *leafError) SafeFormatError(p errbase.Printer) (next error) {
|
|
p.Print(l.msg)
|
|
return nil
|
|
}
|
|
func (l *leafError) SafeDetails() []string {
|
|
return []string{l.msg.Redact().StripMarkers()}
|
|
}
|
|
|
|
func encodeLeaf(_ context.Context, err error) (string, []string, proto.Message) {
|
|
l := err.(*leafError)
|
|
return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.msg)}
|
|
}
|
|
|
|
func decodeLeaf(_ context.Context, _ string, _ []string, payload proto.Message) error {
|
|
m, ok := payload.(*errorspb.StringPayload)
|
|
if !ok {
|
|
// If this ever happens, this means some version of the library
|
|
// (presumably future) changed the payload type, and we're
|
|
// receiving this here. In this case, give up and let
|
|
// DecodeError use the opaque type.
|
|
return nil
|
|
}
|
|
return &leafError{msg: redact.RedactableString(m.Msg)}
|
|
}
|
|
|
|
func init() {
|
|
errbase.RegisterLeafEncoder(errbase.GetTypeKey((*leafError)(nil)), encodeLeaf)
|
|
errbase.RegisterLeafDecoder(errbase.GetTypeKey((*leafError)(nil)), decodeLeaf)
|
|
}
|
|
|
|
// withPrefix is like withMessage but the
|
|
// message can contain redactable and non-redactable parts.
|
|
type withPrefix struct {
|
|
cause error
|
|
prefix redact.RedactableString
|
|
}
|
|
|
|
var _ error = (*withPrefix)(nil)
|
|
var _ fmt.Formatter = (*withPrefix)(nil)
|
|
var _ errbase.SafeFormatter = (*withPrefix)(nil)
|
|
var _ errbase.SafeDetailer = (*withPrefix)(nil)
|
|
|
|
func (l *withPrefix) Error() string {
|
|
if l.prefix == "" {
|
|
return l.cause.Error()
|
|
}
|
|
return fmt.Sprintf("%s: %v", l.prefix.StripMarkers(), l.cause)
|
|
}
|
|
|
|
func (l *withPrefix) Cause() error { return l.cause }
|
|
func (l *withPrefix) Unwrap() error { return l.cause }
|
|
|
|
func (l *withPrefix) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) }
|
|
func (l *withPrefix) SafeFormatError(p errbase.Printer) (next error) {
|
|
p.Print(l.prefix)
|
|
return l.cause
|
|
}
|
|
|
|
func (l *withPrefix) SafeDetails() []string {
|
|
return []string{l.prefix.Redact().StripMarkers()}
|
|
}
|
|
|
|
func encodeWithPrefix(_ context.Context, err error) (string, []string, proto.Message) {
|
|
l := err.(*withPrefix)
|
|
return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.prefix)}
|
|
}
|
|
|
|
func decodeWithPrefix(
|
|
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
|
|
) error {
|
|
m, ok := payload.(*errorspb.StringPayload)
|
|
if !ok {
|
|
// If this ever happens, this means some version of the library
|
|
// (presumably future) changed the payload type, and we're
|
|
// receiving this here. In this case, give up and let
|
|
// DecodeError use the opaque type.
|
|
return nil
|
|
}
|
|
return &withPrefix{cause: cause, prefix: redact.RedactableString(m.Msg)}
|
|
}
|
|
|
|
func init() {
|
|
errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withPrefix)(nil)), encodeWithPrefix)
|
|
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withPrefix)(nil)), decodeWithPrefix)
|
|
}
|
|
|
|
// withNewMessage is like withPrefix but the message completely
|
|
// overrides that of the underlying error.
|
|
type withNewMessage struct {
|
|
cause error
|
|
message redact.RedactableString
|
|
}
|
|
|
|
var _ error = (*withNewMessage)(nil)
|
|
var _ fmt.Formatter = (*withNewMessage)(nil)
|
|
var _ errbase.SafeFormatter = (*withNewMessage)(nil)
|
|
var _ errbase.SafeDetailer = (*withNewMessage)(nil)
|
|
|
|
func (l *withNewMessage) Error() string {
|
|
return l.message.StripMarkers()
|
|
}
|
|
|
|
func (l *withNewMessage) Cause() error { return l.cause }
|
|
func (l *withNewMessage) Unwrap() error { return l.cause }
|
|
|
|
func (l *withNewMessage) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) }
|
|
func (l *withNewMessage) SafeFormatError(p errbase.Printer) (next error) {
|
|
p.Print(l.message)
|
|
return nil /* nil here overrides the cause's message */
|
|
}
|
|
|
|
func (l *withNewMessage) SafeDetails() []string {
|
|
return []string{l.message.Redact().StripMarkers()}
|
|
}
|
|
|
|
func encodeWithNewMessage(_ context.Context, err error) (string, []string, proto.Message) {
|
|
l := err.(*withNewMessage)
|
|
return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.message)}
|
|
}
|
|
|
|
func decodeWithNewMessage(
|
|
_ context.Context, cause error, _ string, _ []string, payload proto.Message,
|
|
) error {
|
|
m, ok := payload.(*errorspb.StringPayload)
|
|
if !ok {
|
|
// If this ever happens, this means some version of the library
|
|
// (presumably future) changed the payload type, and we're
|
|
// receiving this here. In this case, give up and let
|
|
// DecodeError use the opaque type.
|
|
return nil
|
|
}
|
|
return &withNewMessage{cause: cause, message: redact.RedactableString(m.Msg)}
|
|
}
|
|
|
|
func init() {
|
|
errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withNewMessage)(nil)), encodeWithNewMessage)
|
|
errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withNewMessage)(nil)), decodeWithNewMessage)
|
|
}
|