txerr/txerr.go (60 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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 txerr
// Error defines a common error interface type for use with txerr.
// The query and format function support a subset of Error being implemented,
// still it's recommended to implement at least the Error interface for use
// with txerr.
type Error interface {
error
// Op reports the failed operation.
Op() string
// Kind returns the error code, for checking and recovering from errors.
Kind() error
// Message reports an error message for users consumption.
Message() string
// Cause returns the cause of this error. If any.
Cause() error
// optional:
//
// // Context returns a formatted string of the failed operations variables/context
// func Context() string
//
// // Causes collects and returns multiple errors, leading to the current error.
// // Either Cause or Causes should be implemented, but not both.
// Causes() []error
}
// Selective accessors. These accessors allows user to implement a subset of
// Error, but still use the query-functions like Is(err, <kind>).
type (
withOp interface{ Op() string }
withKind interface{ Kind() error }
withContext interface{ Context() string }
withMessage interface{ Message() string }
withChild interface{ Cause() error }
withChildren interface{ Causes() []error }
)
// FindErrWith returns the first error in the error tree, that matches the
// given predicate.
func FindErrWith(in error, pred func(err error) bool) error {
var found error
Iter(in, func(err error) bool {
matches := pred(err)
if matches {
found = err
return false
}
return true
})
return found
}
// Iter iterates the complete error tree calling fn on each error value found.
// The user function fn can stop the iteration by returning false.
func Iter(in error, fn func(err error) bool) {
doIter(in, fn)
}
func doIter(in error, fn func(err error) bool) bool {
for {
if in == nil {
return true
}
if cont := fn(in); !cont {
return cont
}
switch err := in.(type) {
case withChild:
in = err.Cause()
case withChildren:
for _, sub := range err.Causes() {
if cont := doIter(sub, fn); !cont {
return cont
}
}
return true
default:
return true
}
}
}
func directMsg(in error) string {
if err, ok := in.(withMessage); ok {
return err.Message()
}
return ""
}