github.com/cockroachdb/errors@v1.11.1/errutil/redactable.go (about) 1 package errutil 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/cockroachdb/errors/errbase" 8 "github.com/cockroachdb/errors/errorspb" 9 "github.com/cockroachdb/redact" 10 "github.com/gogo/protobuf/proto" 11 ) 12 13 // leafError is like the basic error string in the stdlib except the 14 // message can contain redactable and non-redactable parts. 15 type leafError struct { 16 msg redact.RedactableString 17 } 18 19 var _ error = (*leafError)(nil) 20 var _ fmt.Formatter = (*leafError)(nil) 21 var _ errbase.SafeFormatter = (*leafError)(nil) 22 var _ errbase.SafeDetailer = (*leafError)(nil) 23 24 func (l *leafError) Error() string { return l.msg.StripMarkers() } 25 func (l *leafError) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) } 26 func (l *leafError) SafeFormatError(p errbase.Printer) (next error) { 27 p.Print(l.msg) 28 return nil 29 } 30 func (l *leafError) SafeDetails() []string { 31 return []string{l.msg.Redact().StripMarkers()} 32 } 33 34 func encodeLeaf(_ context.Context, err error) (string, []string, proto.Message) { 35 l := err.(*leafError) 36 return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.msg)} 37 } 38 39 func decodeLeaf(_ context.Context, _ string, _ []string, payload proto.Message) error { 40 m, ok := payload.(*errorspb.StringPayload) 41 if !ok { 42 // If this ever happens, this means some version of the library 43 // (presumably future) changed the payload type, and we're 44 // receiving this here. In this case, give up and let 45 // DecodeError use the opaque type. 46 return nil 47 } 48 return &leafError{msg: redact.RedactableString(m.Msg)} 49 } 50 51 func init() { 52 errbase.RegisterLeafEncoder(errbase.GetTypeKey((*leafError)(nil)), encodeLeaf) 53 errbase.RegisterLeafDecoder(errbase.GetTypeKey((*leafError)(nil)), decodeLeaf) 54 } 55 56 // withPrefix is like withMessage but the 57 // message can contain redactable and non-redactable parts. 58 type withPrefix struct { 59 cause error 60 prefix redact.RedactableString 61 } 62 63 var _ error = (*withPrefix)(nil) 64 var _ fmt.Formatter = (*withPrefix)(nil) 65 var _ errbase.SafeFormatter = (*withPrefix)(nil) 66 var _ errbase.SafeDetailer = (*withPrefix)(nil) 67 68 func (l *withPrefix) Error() string { 69 if l.prefix == "" { 70 return l.cause.Error() 71 } 72 return fmt.Sprintf("%s: %v", l.prefix.StripMarkers(), l.cause) 73 } 74 75 func (l *withPrefix) Cause() error { return l.cause } 76 func (l *withPrefix) Unwrap() error { return l.cause } 77 78 func (l *withPrefix) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) } 79 func (l *withPrefix) SafeFormatError(p errbase.Printer) (next error) { 80 p.Print(l.prefix) 81 return l.cause 82 } 83 84 func (l *withPrefix) SafeDetails() []string { 85 return []string{l.prefix.Redact().StripMarkers()} 86 } 87 88 func encodeWithPrefix(_ context.Context, err error) (string, []string, proto.Message) { 89 l := err.(*withPrefix) 90 return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.prefix)} 91 } 92 93 func decodeWithPrefix( 94 _ context.Context, cause error, _ string, _ []string, payload proto.Message, 95 ) error { 96 m, ok := payload.(*errorspb.StringPayload) 97 if !ok { 98 // If this ever happens, this means some version of the library 99 // (presumably future) changed the payload type, and we're 100 // receiving this here. In this case, give up and let 101 // DecodeError use the opaque type. 102 return nil 103 } 104 return &withPrefix{cause: cause, prefix: redact.RedactableString(m.Msg)} 105 } 106 107 func init() { 108 errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withPrefix)(nil)), encodeWithPrefix) 109 errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withPrefix)(nil)), decodeWithPrefix) 110 } 111 112 // withNewMessage is like withPrefix but the message completely 113 // overrides that of the underlying error. 114 type withNewMessage struct { 115 cause error 116 message redact.RedactableString 117 } 118 119 var _ error = (*withNewMessage)(nil) 120 var _ fmt.Formatter = (*withNewMessage)(nil) 121 var _ errbase.SafeFormatter = (*withNewMessage)(nil) 122 var _ errbase.SafeDetailer = (*withNewMessage)(nil) 123 124 func (l *withNewMessage) Error() string { 125 return l.message.StripMarkers() 126 } 127 128 func (l *withNewMessage) Cause() error { return l.cause } 129 func (l *withNewMessage) Unwrap() error { return l.cause } 130 131 func (l *withNewMessage) Format(s fmt.State, verb rune) { errbase.FormatError(l, s, verb) } 132 func (l *withNewMessage) SafeFormatError(p errbase.Printer) (next error) { 133 p.Print(l.message) 134 return nil /* nil here overrides the cause's message */ 135 } 136 137 func (l *withNewMessage) SafeDetails() []string { 138 return []string{l.message.Redact().StripMarkers()} 139 } 140 141 func encodeWithNewMessage(_ context.Context, err error) (string, []string, proto.Message) { 142 l := err.(*withNewMessage) 143 return l.Error(), l.SafeDetails(), &errorspb.StringPayload{Msg: string(l.message)} 144 } 145 146 func decodeWithNewMessage( 147 _ context.Context, cause error, _ string, _ []string, payload proto.Message, 148 ) error { 149 m, ok := payload.(*errorspb.StringPayload) 150 if !ok { 151 // If this ever happens, this means some version of the library 152 // (presumably future) changed the payload type, and we're 153 // receiving this here. In this case, give up and let 154 // DecodeError use the opaque type. 155 return nil 156 } 157 return &withNewMessage{cause: cause, message: redact.RedactableString(m.Msg)} 158 } 159 160 func init() { 161 errbase.RegisterWrapperEncoder(errbase.GetTypeKey((*withNewMessage)(nil)), encodeWithNewMessage) 162 errbase.RegisterWrapperDecoder(errbase.GetTypeKey((*withNewMessage)(nil)), decodeWithNewMessage) 163 }