mirror of
https://github.com/prometheus/prometheus.git
synced 2026-03-01 21:01:16 -05:00
193 lines
5.6 KiB
Go
193 lines
5.6 KiB
Go
// Copyright 2016 The etcd Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package errors
|
|
|
|
import (
|
|
"bytes"
|
|
stderrors "errors"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// NilOrMultiError type allows combining multiple errors into one.
|
|
type NilOrMultiError struct {
|
|
errs []error
|
|
}
|
|
|
|
// NewMulti returns NilOrMultiError with provided errors added if not nil.
|
|
func NewMulti(errs ...error) *NilOrMultiError {
|
|
m := &NilOrMultiError{}
|
|
m.Add(errs...)
|
|
return m
|
|
}
|
|
|
|
// Add adds single or many errors to the error list. Each error is added only if not nil.
|
|
// If the error is a multiError type, the errors inside multiError are added to the main NilOrMultiError.
|
|
func (e *NilOrMultiError) Add(errs ...error) {
|
|
for _, err := range errs {
|
|
if err == nil {
|
|
continue
|
|
}
|
|
if merr, ok := err.(multiError); ok {
|
|
e.errs = append(e.errs, merr.errs...)
|
|
continue
|
|
}
|
|
e.errs = append(e.errs, err)
|
|
}
|
|
}
|
|
|
|
// Err returns the error list as an Result (also implements error) or nil if it is empty.
|
|
func (e *NilOrMultiError) Err() Result {
|
|
if len(e.errs) == 0 {
|
|
return nil
|
|
}
|
|
return multiError(*e)
|
|
}
|
|
|
|
// Result is extended error interface that allows to use returned read-only multi error in more advanced ways.
|
|
type Result interface {
|
|
error
|
|
|
|
// Errors returns underlying errors.
|
|
Errors() []error
|
|
|
|
// As finds the first error in multiError slice of error chains that matches target, and if so, sets
|
|
// target to that error value and returns true. Otherwise, it returns false.
|
|
//
|
|
// An error matches target if the error's concrete value is assignable to the value
|
|
// pointed to by target, or if the error has a method As(interface{}) bool such that
|
|
// As(target) returns true. In the latter case, the As method is responsible for
|
|
// setting target.
|
|
As(target interface{}) bool
|
|
// Is returns true if any error in multiError's slice of error chains matches the given target or
|
|
// if the target is of multiError type.
|
|
//
|
|
// An error is considered to match a target if it is equal to that target or if
|
|
// it implements a method Is(error) bool such that Is(target) returns true.
|
|
Is(target error) bool
|
|
// Count returns the number of multi error' errors that match the given target.
|
|
// Matching is defined as in Is method.
|
|
Count(target error) int
|
|
}
|
|
|
|
// multiError implements the error and Result interfaces, and it represents NilOrMultiError (in other words []error) with at least one error inside it.
|
|
// NOTE: This type is useful to make sure that NilOrMultiError is not accidentally used for err != nil check.
|
|
type multiError struct {
|
|
errs []error
|
|
}
|
|
|
|
// Errors returns underlying errors.
|
|
func (e multiError) Errors() []error {
|
|
return e.errs
|
|
}
|
|
|
|
// Error returns a concatenated string of the contained errors.
|
|
func (e multiError) Error() string {
|
|
var buf bytes.Buffer
|
|
|
|
if len(e.errs) > 1 {
|
|
fmt.Fprintf(&buf, "%d errors: ", len(e.errs))
|
|
}
|
|
|
|
for i, err := range e.errs {
|
|
if i != 0 {
|
|
buf.WriteString("; ")
|
|
}
|
|
buf.WriteString(err.Error())
|
|
}
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
// As finds the first error in multiError slice of error chains that matches target, and if so, sets
|
|
// target to that error value and returns true. Otherwise, it returns false.
|
|
//
|
|
// An error matches target if the error's concrete value is assignable to the value
|
|
// pointed to by target, or if the error has a method As(interface{}) bool such that
|
|
// As(target) returns true. In the latter case, the As method is responsible for
|
|
// setting target.
|
|
func (e multiError) As(target interface{}) bool {
|
|
if t, ok := target.(*multiError); ok {
|
|
*t = e
|
|
return true
|
|
}
|
|
|
|
for _, err := range e.errs {
|
|
if stderrors.As(err, target) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Is returns true if any error in multiError's slice of error chains matches the given target or
|
|
// if the target is of multiError type.
|
|
//
|
|
// An error is considered to match a target if it is equal to that target or if
|
|
// it implements a method Is(error) bool such that Is(target) returns true.
|
|
func (e multiError) Is(target error) bool {
|
|
if m, ok := target.(multiError); ok {
|
|
if len(m.errs) != len(e.errs) {
|
|
return false
|
|
}
|
|
for i := 0; i < len(e.errs); i++ {
|
|
if !stderrors.Is(m.errs[i], e.errs[i]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
for _, err := range e.errs {
|
|
if stderrors.Is(err, target) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Count returns the number of all multi error' errors that match the given target (including nested multi errors).
|
|
// Matching is defined as in Is method.
|
|
func (e multiError) Count(target error) (count int) {
|
|
for _, err := range e.errs {
|
|
if inner, ok := AsMulti(err); ok {
|
|
count += inner.Count(target)
|
|
continue
|
|
}
|
|
|
|
if stderrors.Is(err, target) {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
// As casts error to multi error read only interface. It returns multi error and true if error matches multi error as
|
|
// defined by As method. If returns false if no multi error can be found.
|
|
func AsMulti(err error) (Result, bool) {
|
|
m := multiError{}
|
|
if !stderrors.As(err, &m) {
|
|
return nil, false
|
|
}
|
|
return m, true
|
|
}
|
|
|
|
// CloseAll closes all given closers while recording error in multiError.
|
|
func CloseAll(cs []io.Closer) error {
|
|
errs := NewMulti()
|
|
for _, c := range cs {
|
|
errs.Add(c.Close())
|
|
}
|
|
return errs.Err()
|
|
}
|