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  }