mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 20:00:07 +00:00
Merge pull request #135419 from pohly/apimachinery-handle-errors-helper
apimachinery: clarify ErrorHandler and provide helper for formatting
This commit is contained in:
@@ -17,14 +17,17 @@ limitations under the License.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/klog/v2/textlogger"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -154,8 +157,37 @@ var ErrorHandlers = []ErrorHandler{
|
||||
backoffError(1 * time.Millisecond),
|
||||
}
|
||||
|
||||
// ErrorHandler is called indirectly through [HandleError], [HandleErrorWithContext] or [HandleErrorWithLogger].
|
||||
// It is passed the same parameters that a structured logging backend needs to log a problem.
|
||||
// It follows the semantic described for [HandleErrorWithContext] and [logr.Logger.Error]:
|
||||
// - err is optional and may be nil
|
||||
// - msg is string that describes the problem
|
||||
// - keysAndValues contains additional information that varies between different occurrences of the problem
|
||||
//
|
||||
// [ErrorToString] can be used to convert these parameters into a single string, using the klog text output.
|
||||
type ErrorHandler func(ctx context.Context, err error, msg string, keysAndValues ...interface{})
|
||||
|
||||
// ErrorToString takes the parameters passed to [ErrorHandler] and
|
||||
// formats them as a string using the klog text output.
|
||||
//
|
||||
// If any of the values is a multi-line string, then the resulting
|
||||
// string also uses line breaks and indention for the sake of readability.
|
||||
// Does not include a trailing newline.
|
||||
//
|
||||
// Use errors.New if an error instead of a string is needed.
|
||||
func ErrorToString(err error, msg string, keysAndValues ...interface{}) string {
|
||||
var buffer bytes.Buffer
|
||||
config := textlogger.NewConfig(
|
||||
textlogger.Output(&buffer),
|
||||
textlogger.WithHeader(false),
|
||||
)
|
||||
logger := textlogger.NewLogger(config)
|
||||
logger.Error(err, msg, keysAndValues...)
|
||||
result := buffer.String()
|
||||
result = strings.TrimSpace(result)
|
||||
return result
|
||||
}
|
||||
|
||||
// HandlerError is a method to invoke when a non-user facing piece of code cannot
|
||||
// return an error and needs to indicate it has been ignored. Invoking this method
|
||||
// is preferable to logging the error - the default behavior is to log but the
|
||||
|
||||
@@ -311,3 +311,39 @@ func TestHandleError(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorToString(t *testing.T) {
|
||||
for name, tt := range map[string]struct {
|
||||
err error
|
||||
msg string
|
||||
kvs []any
|
||||
expectString string
|
||||
}{
|
||||
"simple": {
|
||||
errors.New("some error"),
|
||||
"Unhandled error",
|
||||
nil,
|
||||
`"Unhandled error" err="some error"`,
|
||||
},
|
||||
"nil-error": {
|
||||
nil,
|
||||
"Some problem occurred",
|
||||
nil,
|
||||
`"Some problem occurred"`,
|
||||
},
|
||||
"keys-and-values": {
|
||||
errors.New("some error"),
|
||||
"Some error occurred",
|
||||
[]any{"str", "foobar", "int", 1, "multiLine", "line 1\nline 2"},
|
||||
`"Some error occurred" err="some error" str="foobar" int=1 multiLine=<
|
||||
line 1
|
||||
line 2
|
||||
>`,
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
actualString := ErrorToString(tt.err, tt.msg, tt.kvs...)
|
||||
assert.Equal(t, tt.expectString, actualString)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user