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 }