github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/message/error_message.go (about)

     1  package message
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/mongodb/grip/level"
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  type errorComposerWrap struct {
    12  	err    error
    13  	cached string
    14  	Composer
    15  }
    16  
    17  // NewErrorWrappedComposer provvides a way to construct a log message
    18  // that annotates an error.
    19  func NewErrorWrappedComposer(err error, m Composer) ErrorComposer {
    20  	return &errorComposerWrap{
    21  		err:      err,
    22  		Composer: m,
    23  	}
    24  }
    25  
    26  // NewErrorWrapMessage produces a fully configured message.Composer
    27  // that combines the functionality of an Error composer that renders a
    28  // loggable error message for non-nil errors with a normal formatted
    29  // message (e.g. fmt.Sprintf). These messages only log if the error is
    30  // non-nil.
    31  func NewErrorWrapMessage(p level.Priority, err error, base string, args ...interface{}) ErrorComposer {
    32  	return NewErrorWrappedComposer(err, NewFormattedMessage(p, base, args...))
    33  }
    34  
    35  // NewErrorWrap produces a message.Composer that combines the
    36  // functionality of an Error composer that renders a loggable error
    37  // message for non-nil errors with a normal formatted message
    38  // (e.g. fmt.Sprintf). These messages only log if the error is
    39  // non-nil.
    40  func NewErrorWrap(err error, base string, args ...interface{}) ErrorComposer {
    41  	return NewErrorWrappedComposer(err, NewFormatted(base, args...))
    42  }
    43  
    44  // WrapError wraps an error and creates a composer converting the
    45  // argument into a composer in the same manner as the front end logging methods.
    46  func WrapError(err error, m interface{}) ErrorComposer {
    47  	return NewErrorWrappedComposer(err, ConvertToComposer(level.Priority(0), m))
    48  }
    49  
    50  // WrapErrorf wraps an error and creates a composer using a
    51  // Sprintf-style formated composer.
    52  func WrapErrorf(err error, msg string, args ...interface{}) ErrorComposer {
    53  	return NewErrorWrappedComposer(err, NewFormatted(msg, args...))
    54  }
    55  
    56  func (m *errorComposerWrap) String() string {
    57  	if m.cached == "" {
    58  		context := m.Composer.String()
    59  		if context != "" {
    60  			m.cached = fmt.Sprintf("%s: %v", context, m.err.Error())
    61  		} else {
    62  			m.cached = m.err.Error()
    63  		}
    64  	}
    65  
    66  	return m.cached
    67  }
    68  
    69  func (m *errorComposerWrap) Error() string { return m.String() }
    70  func (m *errorComposerWrap) Cause() error  { return m.err }
    71  func (m *errorComposerWrap) Format(s fmt.State, verb rune) {
    72  	switch verb {
    73  	case 'v':
    74  		if s.Flag('+') {
    75  			fmt.Fprintf(s, "%+v\n", errors.Cause(m.err))
    76  			_, _ = io.WriteString(s, m.String())
    77  			return
    78  		}
    79  		fallthrough
    80  	case 's', 'q':
    81  		_, _ = io.WriteString(s, m.Error())
    82  	}
    83  }
    84  
    85  func (m *errorComposerWrap) Loggable() bool {
    86  	return m.err != nil
    87  }
    88  
    89  func (m *errorComposerWrap) Raw() interface{} {
    90  	errStr := m.err.Error()
    91  	out := Fields{
    92  		"error": errStr,
    93  	}
    94  
    95  	if m.Composer.Loggable() {
    96  		// special handling for fields - merge keys in with output keys
    97  		switch t := m.Composer.(type) {
    98  		case *fieldMessage:
    99  			t.fields["error"] = errStr
   100  			out = t.fields
   101  		default:
   102  			out["context"] = m.Composer.Raw()
   103  		}
   104  	}
   105  
   106  	ext := fmt.Sprintf("%+v", m.err)
   107  	if ext != errStr {
   108  		out["extended"] = ext
   109  	}
   110  
   111  	return out
   112  }
   113  
   114  func (m *errorComposerWrap) Annotate(k string, v interface{}) error {
   115  	return m.Composer.Annotate(k, v)
   116  }