Chore: Add errutils helpers (#73577)

Add helpers for the errutil package in favor of errutil.NewBase.
This commit is contained in:
Marcus Efraimsson
2023-08-22 12:52:24 +02:00
committed by GitHub
parent 1cc226e689
commit 040b7d2571
45 changed files with 261 additions and 161 deletions

View File

@@ -11,7 +11,7 @@ import (
"github.com/grafana/grafana/pkg/util/errutil"
)
var ErrNonGrafanaError = errutil.NewBase(errutil.StatusInternal, "core.MalformedError")
var ErrNonGrafanaError = errutil.Internal("core.MalformedError")
var defaultLogger = log.New("requestErrors")
// ErrorOptions is a container for functional options passed to [Write].

View File

@@ -14,7 +14,7 @@ import (
func TestWrite(t *testing.T) {
ctx := context.Background()
const msgID = "test.thisIsExpected"
base := errutil.NewBase(errutil.StatusTimeout, msgID)
base := errutil.Timeout(msgID)
handler := func(writer http.ResponseWriter, request *http.Request) {
Write(ctx, base.Errorf("got expected error"), writer)
}

View File

@@ -41,6 +41,108 @@ func NewBase(reason StatusReason, msgID string, opts ...BaseOpt) Base {
return b
}
// NotFound initializes a new [Base] error with reason StatusNotFound
// that is used to construct [Error]. The msgID is passed to the caller
// to serve as the base for user facing error messages.
//
// msgID should be structured as component.errorBrief, for example
//
// folder.notFound
// plugin.notRegistered
func NotFound(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusNotFound, msgID, opts...)
}
// BadRequest initializes a new [Base] error with reason StatusBadRequest
// that is used to construct [Error]. The msgID is passed to the caller
// to serve as the base for user facing error messages.
//
// msgID should be structured as component.errorBrief, for example
//
// query.invalidDatasourceId
// sse.dataQueryError
func BadRequest(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusBadRequest, msgID, opts...)
}
// ValidationFailed initializes a new [Base] error with reason StatusValidationFailed
// that is used to construct [Error]. The msgID is passed to the caller
// to serve as the base for user facing error messages.
//
// msgID should be structured as component.errorBrief, for example
//
// datasource.nameInvalid
// datasource.urlInvalid
// serviceaccounts.errInvalidInput
func ValidationFailed(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusValidationFailed, msgID, opts...)
}
// Internal initializes a new [Base] error with reason StatusInternal
// that is used to construct [Error]. The msgID is passed to the caller
// to serve as the base for user facing error messages.
//
// msgID should be structured as component.errorBrief, for example
//
// sqleng.connectionError
// plugin.downstreamError
func Internal(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusInternal, msgID, opts...)
}
// Timeout initializes a new [Base] error with reason StatusTimeout.
//
// area.timeout
func Timeout(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusTimeout, msgID, opts...)
}
// Unauthorized initializes a new [Base] error with reason StatusUnauthorized
// that is used to construct [Error]. The msgID is passed to the caller
// to serve as the base for user facing error messages.
//
// msgID should be structured as component.errorBrief, for example
//
// auth.unauthorized
func Unauthorized(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusUnauthorized, msgID, opts...)
}
// Forbidden initializes a new [Base] error with reason StatusForbidden
// that is used to construct [Error]. The msgID is passed to the caller
// to serve as the base for user facing error messages.
//
// msgID should be structured as component.errorBrief, for example
//
// quota.disabled
// user.sync.forbidden
func Forbidden(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusForbidden, msgID, opts...)
}
// TooManyRequests initializes a new [Base] error with reason StatusTooManyRequests
// that is used to construct [Error]. The msgID is passed to the caller
// to serve as the base for user facing error messages.
//
// msgID should be structured as component.errorBrief, for example
//
// area.tooManyRequests
func TooManyRequests(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusTooManyRequests, msgID, opts...)
}
// NotImplemented initializes a new [Base] error with reason StatusNotImplemented
// that is used to construct [Error]. The msgID is passed to the caller
// to serve as the base for user facing error messages.
//
// msgID should be structured as component.errorBrief, for example
//
// plugin.notImplemented
// auth.identity.unsupported
func NotImplemented(msgID string, opts ...BaseOpt) Base {
return NewBase(StatusNotImplemented, msgID, opts...)
}
type BaseOpt func(Base) Base
// WithLogLevel sets a custom log level for all errors instantiated from

View File

@@ -15,9 +15,9 @@ var (
// same error message for the frontend statically within the
// package.
errAbsPath = errutil.NewBase(errutil.StatusBadRequest, "shorturl.absolutePath")
errInvalidPath = errutil.NewBase(errutil.StatusBadRequest, "shorturl.invalidPath")
errUnexpected = errutil.NewBase(errutil.StatusInternal, "shorturl.unexpected")
errAbsPath = errutil.BadRequest("shorturl.absolutePath")
errInvalidPath = errutil.BadRequest("shorturl.invalidPath")
errUnexpected = errutil.Internal("shorturl.unexpected")
)
func Example() {

View File

@@ -10,8 +10,8 @@ import (
)
func TestBase_Is(t *testing.T) {
baseNotFound := NewBase(StatusNotFound, "test.notFound")
baseInternal := NewBase(StatusInternal, "test.internal")
baseNotFound := NotFound("test.notFound")
baseInternal := Internal("test.internal")
tests := []struct {
Base Base

View File

@@ -11,7 +11,7 @@ import (
)
func TestTemplate(t *testing.T) {
tmpl := errutil.NewBase(errutil.StatusInternal, "template.sampleError").MustTemplate("[{{ .Public.user }}] got error: {{ .Error }}")
tmpl := errutil.Internal("template.sampleError").MustTemplate("[{{ .Public.user }}] got error: {{ .Error }}")
err := tmpl.Build(errutil.TemplateData{
Public: map[string]interface{}{
"user": "grot the bot",
@@ -31,7 +31,7 @@ func TestTemplate(t *testing.T) {
func ExampleTemplate() {
// Initialization, this is typically done on a package or global
// level.
var tmpl = errutil.NewBase(errutil.StatusInternal, "template.sampleError").MustTemplate("[{{ .Public.user }}] got error: {{ .Error }}")
var tmpl = errutil.Internal("template.sampleError").MustTemplate("[{{ .Public.user }}] got error: {{ .Error }}")
// Construct an error based on the template.
err := tmpl.Build(errutil.TemplateData{
@@ -50,12 +50,10 @@ func ExampleTemplate() {
func ExampleTemplate_public() {
// Initialization, this is typically done on a package or global
// level.
var tmpl = errutil.
NewBase(errutil.StatusInternal, "template.sampleError").
MustTemplate(
"[{{ .Public.user }}] got error: {{ .Error }}",
errutil.WithPublic("Oh, no, error for {{ .Public.user }}"),
)
var tmpl = errutil.Internal("template.sampleError").MustTemplate(
"[{{ .Public.user }}] got error: {{ .Error }}",
errutil.WithPublic("Oh, no, error for {{ .Public.user }}"),
)
// Construct an error based on the template.
//nolint:errorlint