github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/util/errors.go (about)

     1  package util
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/go-kit/log/level"
    10  	"google.golang.org/grpc/codes"
    11  	"google.golang.org/grpc/status"
    12  
    13  	"github.com/grafana/loki/pkg/util/log"
    14  )
    15  
    16  // LogError logs any error returned by f; useful when deferring Close etc.
    17  func LogError(message string, f func() error) {
    18  	if err := f(); err != nil {
    19  		level.Error(log.Logger).Log("message", message, "error", err)
    20  	}
    21  }
    22  
    23  // LogError logs any error returned by f; useful when deferring Close etc.
    24  func LogErrorWithContext(ctx context.Context, message string, f func() error) {
    25  	if err := f(); err != nil {
    26  		level.Error(log.WithContext(ctx, log.Logger)).Log("message", message, "error", err)
    27  	}
    28  }
    29  
    30  // The MultiError type implements the error interface, and contains the
    31  // Errors used to construct it.
    32  type MultiError []error
    33  
    34  // Returns a concatenated string of the contained errors
    35  func (es MultiError) Error() string {
    36  	var buf bytes.Buffer
    37  
    38  	if len(es) > 1 {
    39  		_, _ = fmt.Fprintf(&buf, "%d errors: ", len(es))
    40  	}
    41  
    42  	for i, err := range es {
    43  		if i != 0 {
    44  			buf.WriteString("; ")
    45  		}
    46  		buf.WriteString(err.Error())
    47  	}
    48  
    49  	return buf.String()
    50  }
    51  
    52  // Add adds the error to the error list if it is not nil.
    53  func (es *MultiError) Add(err error) {
    54  	if err == nil {
    55  		return
    56  	}
    57  	if merr, ok := err.(MultiError); ok {
    58  		*es = append(*es, merr...)
    59  	} else {
    60  		*es = append(*es, err)
    61  	}
    62  }
    63  
    64  // Err returns the error list as an error or nil if it is empty.
    65  func (es MultiError) Err() error {
    66  	if len(es) == 0 {
    67  		return nil
    68  	}
    69  	return es
    70  }
    71  
    72  // Is tells if all errors are the same as the target error.
    73  func (es MultiError) Is(target error) bool {
    74  	if len(es) == 0 {
    75  		return false
    76  	}
    77  	for _, err := range es {
    78  		if !errors.Is(err, target) {
    79  			return false
    80  		}
    81  	}
    82  	return true
    83  }
    84  
    85  // IsDeadlineExceeded tells if all errors are either context.DeadlineExceeded or grpc codes.DeadlineExceeded.
    86  func (es MultiError) IsDeadlineExceeded() bool {
    87  	if len(es) == 0 {
    88  		return false
    89  	}
    90  	for _, err := range es {
    91  		if errors.Is(err, context.DeadlineExceeded) {
    92  			continue
    93  		}
    94  		s, ok := status.FromError(err)
    95  		if ok && s.Code() == codes.DeadlineExceeded {
    96  			continue
    97  		}
    98  		return false
    99  	}
   100  	return true
   101  }
   102  
   103  // IsConnCanceled returns true, if error is from a closed gRPC connection.
   104  // copied from https://github.com/etcd-io/etcd/blob/7f47de84146bdc9225d2080ec8678ca8189a2d2b/clientv3/client.go#L646
   105  func IsConnCanceled(err error) bool {
   106  	if err == nil {
   107  		return false
   108  	}
   109  
   110  	// >= gRPC v1.23.x
   111  	s, ok := status.FromError(err)
   112  	if ok {
   113  		// connection is canceled or server has already closed the connection
   114  		return s.Code() == codes.Canceled || s.Message() == "transport is closing"
   115  	}
   116  
   117  	return false
   118  }