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

     1  // Error Messages
     2  //
     3  // The error message composers underpin the Catch<> logging messages,
     4  // which allow you to log error messages but let the logging system
     5  // elide logging for nil errors.
     6  package message
     7  
     8  import (
     9  	"fmt"
    10  	"io"
    11  
    12  	"github.com/mongodb/grip/level"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  type errorMessage struct {
    17  	ErrorValue              string `bson:"error" json:"error" yaml:"error"`
    18  	Extended                string `bson:"extended,omitempty" json:"extended,omitempty" yaml:"extended,omitempty"`
    19  	Base                    `bson:"metadata" json:"metadata" yaml:"metadata"`
    20  	err                     error
    21  	includeExtendedMetadata bool
    22  }
    23  
    24  // NewErrorMessage takes an error object and returns an ErrorComposer instance
    25  // that only renders a loggable message when the error is non-nil.
    26  //
    27  // These composers also implement the error interface and the pkg/errors.Causer
    28  // interface and so can be passed as errors and used with existing
    29  // error-wrapping mechanisms.
    30  func NewErrorMessage(p level.Priority, err error) ErrorComposer {
    31  	m := &errorMessage{
    32  		err: err,
    33  	}
    34  	_ = m.SetPriority(p)
    35  	return m
    36  }
    37  
    38  // NewError returns an ErrorComposer, like NewErrorMessage, but
    39  // without the requirement to specify priority, which you may wish to
    40  // specify directly.
    41  func NewError(err error) ErrorComposer {
    42  	return &errorMessage{
    43  		err: err,
    44  	}
    45  }
    46  
    47  // NewExtendedErrorMessage is like NewErrorMessage, but also collects extended
    48  // logging metadata.
    49  func NewExtendedErrorMessage(p level.Priority, err error) ErrorComposer {
    50  	m := &errorMessage{
    51  		err:                     err,
    52  		includeExtendedMetadata: true,
    53  	}
    54  	_ = m.SetPriority(p)
    55  	return m
    56  }
    57  
    58  // NewExtendedError is like NewError, but also collects extended logging
    59  // metadata.
    60  func NewExtendedError(err error) ErrorComposer {
    61  	return &errorMessage{
    62  		err:                     err,
    63  		includeExtendedMetadata: true,
    64  	}
    65  }
    66  
    67  func (e *errorMessage) String() string {
    68  	if e.err == nil {
    69  		return ""
    70  	}
    71  	e.ErrorValue = e.err.Error()
    72  	return e.ErrorValue
    73  }
    74  
    75  func (e *errorMessage) Loggable() bool {
    76  	return e.err != nil
    77  }
    78  
    79  func (e *errorMessage) Raw() interface{} {
    80  	_ = e.Collect(e.includeExtendedMetadata)
    81  	_ = e.String()
    82  
    83  	extended := fmt.Sprintf("%+v", e.err)
    84  	if extended != e.ErrorValue {
    85  		e.Extended = extended
    86  	}
    87  
    88  	return e
    89  }
    90  
    91  func (e *errorMessage) Error() string { return e.String() }
    92  func (e *errorMessage) Cause() error  { return e.err }
    93  func (e *errorMessage) Format(s fmt.State, verb rune) {
    94  	switch verb {
    95  	case 'v':
    96  		if s.Flag('+') {
    97  			fmt.Fprintf(s, "%+v\n", errors.Cause(e.err))
    98  			_, _ = io.WriteString(s, e.String())
    99  			return
   100  		}
   101  		fallthrough
   102  	case 's', 'q':
   103  		_, _ = io.WriteString(s, e.Error())
   104  	}
   105  }