mirror of
https://github.com/SigNoz/signoz.git
synced 2026-05-25 19:30:33 +01:00
Compare commits
1 Commits
emdash/tra
...
tvats-pkg-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03112ebd5b |
@@ -2391,6 +2391,8 @@ components:
|
||||
type: object
|
||||
ErrorsJSON:
|
||||
properties:
|
||||
attrs:
|
||||
$ref: '#/components/schemas/ErrorsResponseattributes'
|
||||
code:
|
||||
type: string
|
||||
errors:
|
||||
@@ -2399,17 +2401,45 @@ components:
|
||||
type: array
|
||||
message:
|
||||
type: string
|
||||
retry:
|
||||
$ref: '#/components/schemas/ErrorsResponseretryjson'
|
||||
type:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
- code
|
||||
- message
|
||||
type: object
|
||||
ErrorsResponseattributes:
|
||||
additionalProperties: {}
|
||||
type: object
|
||||
ErrorsResponseerroradditional:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
type: object
|
||||
ErrorsResponseretryjson:
|
||||
properties:
|
||||
after:
|
||||
description: Retry delay in google.protobuf.Duration JSON form. Present
|
||||
only when policy is "after".
|
||||
example: 5.5s
|
||||
format: duration
|
||||
type: string
|
||||
policy:
|
||||
$ref: '#/components/schemas/ErrorsResponseretrypolicy'
|
||||
type: object
|
||||
ErrorsResponseretrypolicy:
|
||||
enum:
|
||||
- never
|
||||
- immediate
|
||||
- backoff
|
||||
- after
|
||||
- after_fix
|
||||
- after_auth
|
||||
type: string
|
||||
FactoryResponse:
|
||||
properties:
|
||||
healthy:
|
||||
|
||||
@@ -894,7 +894,7 @@ func TestEmailGetPassword(t *testing.T) {
|
||||
if len(tc.errMsg) > 0 {
|
||||
require.Error(t, err)
|
||||
if errors.Asc(err, errors.CodeInternal) {
|
||||
_, _, errMsg, _, _, _ := errors.Unwrapb(err)
|
||||
_, _, errMsg, _, _, _, _, _ := errors.Unwrapb(err)
|
||||
require.Contains(t, errMsg, tc.errMsg)
|
||||
} else {
|
||||
require.Contains(t, err.Error(), tc.errMsg)
|
||||
|
||||
@@ -327,7 +327,7 @@ func TestPagerDutyTemplating(t *testing.T) {
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
if errors.Asc(err, errors.CodeInternal) {
|
||||
_, _, errMsg, _, _, _ := errors.Unwrapb(err)
|
||||
_, _, errMsg, _, _, _, _, _ := errors.Unwrapb(err)
|
||||
require.Contains(t, errMsg, tc.errMsg)
|
||||
} else {
|
||||
require.Contains(t, err.Error(), tc.errMsg)
|
||||
|
||||
@@ -4,12 +4,13 @@ import (
|
||||
"errors" //nolint:depguard
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
// base is the fundamental struct that implements the error interface.
|
||||
// The order of the struct is 'TCMEUAS'.
|
||||
type base struct {
|
||||
// t denotes the custom type of the error.
|
||||
t typ
|
||||
@@ -22,9 +23,15 @@ type base struct {
|
||||
// u denotes the url for the documentation (if present) for the error.
|
||||
u string
|
||||
// a denotes any additional error messages (if present).
|
||||
// NOTE: use attrs['suggestions'] for additional structured suggestions instead of this field.
|
||||
a []string
|
||||
// s contains the stacktrace captured at error creation time.
|
||||
s fmt.Stringer
|
||||
// r is the retry strategy for the error, if applicable.
|
||||
r retry
|
||||
// attrs contains any additional attributes for the error, if present.
|
||||
// attrs is declared to be map[string]any, however map[string][]string is expected to be used for values.
|
||||
attrs map[string]any
|
||||
}
|
||||
|
||||
// Stacktrace returns the stacktrace captured at error creation time, formatted as a string.
|
||||
@@ -39,13 +46,15 @@ func (b *base) Stacktrace() string {
|
||||
// and returns a new base error.
|
||||
func (b *base) WithStacktrace(s string) *base {
|
||||
return &base{
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: b.u,
|
||||
a: b.a,
|
||||
s: rawStacktrace(s),
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: b.u,
|
||||
a: b.a,
|
||||
s: rawStacktrace(s),
|
||||
r: b.r,
|
||||
attrs: b.attrs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,19 +116,21 @@ func Wrap(cause error, t typ, code Code, message string) *base {
|
||||
|
||||
// WithAdditionalf adds an additional error message to the existing error.
|
||||
func WithAdditionalf(cause error, format string, args ...any) *base {
|
||||
t, c, m, e, u, a := Unwrapb(cause)
|
||||
t, c, m, e, u, a, r, attrs := Unwrapb(cause)
|
||||
var s fmt.Stringer
|
||||
if original, ok := cause.(*base); ok {
|
||||
s = original.s
|
||||
}
|
||||
b := &base{
|
||||
t: t,
|
||||
c: c,
|
||||
m: m,
|
||||
e: e,
|
||||
u: u,
|
||||
a: a,
|
||||
s: s,
|
||||
t: t,
|
||||
c: c,
|
||||
m: m,
|
||||
e: e,
|
||||
u: u,
|
||||
a: a,
|
||||
s: s,
|
||||
r: r,
|
||||
attrs: attrs,
|
||||
}
|
||||
|
||||
return b.WithAdditional(append(a, fmt.Sprintf(format, args...))...)
|
||||
@@ -128,55 +139,197 @@ func WithAdditionalf(cause error, format string, args ...any) *base {
|
||||
// WithUrl adds a url to the base error and returns a new base error.
|
||||
func (b *base) WithUrl(u string) *base {
|
||||
return &base{
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: u,
|
||||
a: b.a,
|
||||
s: b.s,
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: u,
|
||||
a: b.a,
|
||||
s: b.s,
|
||||
r: b.r,
|
||||
attrs: b.attrs,
|
||||
}
|
||||
}
|
||||
|
||||
// WithAdditional adds additional messages to the base error and returns a new base error.
|
||||
func (b *base) WithAdditional(a ...string) *base {
|
||||
return &base{
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: b.u,
|
||||
a: a,
|
||||
s: b.s,
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: b.u,
|
||||
a: a,
|
||||
s: b.s,
|
||||
r: b.r,
|
||||
attrs: b.attrs,
|
||||
}
|
||||
}
|
||||
|
||||
// WithRetry adds retry metadata to the base error and returns a new base error.
|
||||
func (b *base) WithRetry(r retry) *base {
|
||||
return &base{
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: b.u,
|
||||
a: b.a,
|
||||
s: b.s,
|
||||
r: r,
|
||||
attrs: b.attrs,
|
||||
}
|
||||
}
|
||||
|
||||
// setAttrs replaces the value at key with the given values and returns a new base error.
|
||||
// Values are always stored as []string under a stable key.
|
||||
// This helper is not exported; use WithSuggestions (or add a new With* method) instead.
|
||||
func (b *base) setAttrs(key string, values ...string) *base {
|
||||
copiedAttrs := make(map[string]any, len(b.attrs)+1)
|
||||
maps.Copy(copiedAttrs, b.attrs)
|
||||
|
||||
replacement := make([]string, len(values))
|
||||
copy(replacement, values)
|
||||
copiedAttrs[key] = replacement
|
||||
|
||||
return &base{
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: b.u,
|
||||
a: b.a,
|
||||
s: b.s,
|
||||
r: b.r,
|
||||
attrs: copiedAttrs,
|
||||
}
|
||||
}
|
||||
|
||||
// addAttrs appends additional values to the existing list at key and returns a new base error.
|
||||
// Values are always stored as []string under a stable key.
|
||||
// This helper is not exported; use AddSuggestions, AddWarnings, or AddInvalidReferences,
|
||||
// or add a new method that calls addAttrs for any specific attributes.
|
||||
func (b *base) addAttrs(key string, values ...string) *base {
|
||||
copiedAttrs := make(map[string]any, len(b.attrs)+1)
|
||||
maps.Copy(copiedAttrs, b.attrs)
|
||||
|
||||
if len(values) > 0 {
|
||||
existing, _ := copiedAttrs[key].([]string)
|
||||
merged := make([]string, 0, len(existing)+len(values))
|
||||
merged = append(merged, existing...)
|
||||
merged = append(merged, values...)
|
||||
copiedAttrs[key] = merged
|
||||
}
|
||||
|
||||
return &base{
|
||||
t: b.t,
|
||||
c: b.c,
|
||||
m: b.m,
|
||||
e: b.e,
|
||||
u: b.u,
|
||||
a: b.a,
|
||||
s: b.s,
|
||||
r: b.r,
|
||||
attrs: copiedAttrs,
|
||||
}
|
||||
}
|
||||
|
||||
// WithSuggestions replaces the list of suggestions on the base error.
|
||||
func (b *base) WithSuggestions(suggestions ...string) *base {
|
||||
return b.setAttrs("suggestions", suggestions...)
|
||||
}
|
||||
|
||||
// AddSuggestions appends to the existing list of suggestions on the base error.
|
||||
func (b *base) AddSuggestions(suggestions ...string) *base {
|
||||
return b.addAttrs("suggestions", suggestions...)
|
||||
}
|
||||
|
||||
// WithInvalidReference replaces the list of invalid references on the base error with a single entry.
|
||||
func (b *base) WithInvalidReference(invalidReference string) *base {
|
||||
return b.setAttrs("invalidReferences", invalidReference)
|
||||
}
|
||||
|
||||
// WithInvalidReferences replaces the list of invalid references on the base error.
|
||||
func (b *base) WithInvalidReferences(invalidReferences ...string) *base {
|
||||
return b.setAttrs("invalidReferences", invalidReferences...)
|
||||
}
|
||||
|
||||
// AddInvalidReference appends a single invalid reference to the existing list on the base error.
|
||||
func (b *base) AddInvalidReference(invalidReference string) *base {
|
||||
return b.addAttrs("invalidReferences", invalidReference)
|
||||
}
|
||||
|
||||
// AddInvalidReferences appends to the existing list of invalid references on the base error.
|
||||
func (b *base) AddInvalidReferences(invalidReferences ...string) *base {
|
||||
return b.addAttrs("invalidReferences", invalidReferences...)
|
||||
}
|
||||
|
||||
// WithWarnings replaces the list of warnings on the base error.
|
||||
func (b *base) WithWarnings(warnings ...string) *base {
|
||||
return b.setAttrs("warnings", warnings...)
|
||||
}
|
||||
|
||||
// AddWarnings appends to the existing list of warnings on the base error.
|
||||
func (b *base) AddWarnings(warnings ...string) *base {
|
||||
return b.addAttrs("warnings", warnings...)
|
||||
}
|
||||
|
||||
// WithRetryNever sets the retry policy to Never.
|
||||
func (b *base) WithRetryNever() *base {
|
||||
return b.WithRetry(retry{policy: RetryNever})
|
||||
}
|
||||
|
||||
// WithRetryImmediate sets the retry policy to Immediate.
|
||||
func (b *base) WithRetryImmediate() *base {
|
||||
return b.WithRetry(retry{policy: RetryImmediate})
|
||||
}
|
||||
|
||||
// WithRetryBackoff sets the retry policy to Backoff.
|
||||
func (b *base) WithRetryBackoff() *base {
|
||||
return b.WithRetry(retry{policy: RetryBackoff})
|
||||
}
|
||||
|
||||
// WithRetryAfter sets the retry policy to After and requires a delay.
|
||||
func (b *base) WithRetryAfter(delay time.Duration) *base {
|
||||
return b.WithRetry(retry{policy: RetryAfter, after: delay})
|
||||
}
|
||||
|
||||
// WithRetryAfterFix sets the retry policy to AfterFix.
|
||||
func (b *base) WithRetryAfterFix() *base {
|
||||
return b.WithRetry(retry{policy: RetryAfterFix})
|
||||
}
|
||||
|
||||
// WithRetryAfterAuth sets the retry policy to AfterAuth.
|
||||
func (b *base) WithRetryAfterAuth() *base {
|
||||
return b.WithRetry(retry{policy: RetryAfterAuth})
|
||||
}
|
||||
|
||||
// Unwrapb is a combination of built-in errors.As and type casting.
|
||||
// It finds the first error in cause that matches base,
|
||||
// and if one is found, returns the individual fields of base.
|
||||
// Otherwise, it returns TypeInternal, the original error string
|
||||
// and the error itself.
|
||||
//
|
||||
//nolint:staticcheck // ST1008: intentional return order matching struct field order (TCMEUA)
|
||||
func Unwrapb(cause error) (typ, Code, string, error, string, []string) {
|
||||
//nolint:staticcheck // ST1008: intentional return order matching struct field order (TCMEUARA)
|
||||
func Unwrapb(cause error) (typ, Code, string, error, string, []string, retry, map[string]any) {
|
||||
base, ok := cause.(*base)
|
||||
if ok {
|
||||
return base.t, base.c, base.m, base.e, base.u, base.a
|
||||
return base.t, base.c, base.m, base.e, base.u, base.a, base.r, base.attrs
|
||||
}
|
||||
|
||||
return TypeInternal, CodeUnknown, cause.Error(), cause, "", []string{}
|
||||
return TypeInternal, CodeUnknown, cause.Error(), cause, "", []string{}, retry{policy: RetryNever}, map[string]any{}
|
||||
}
|
||||
|
||||
// Ast checks if the provided error matches the specified custom error type.
|
||||
func Ast(cause error, typ typ) bool {
|
||||
t, _, _, _, _, _ := Unwrapb(cause)
|
||||
t, _, _, _, _, _, _, _ := Unwrapb(cause)
|
||||
|
||||
return t == typ
|
||||
}
|
||||
|
||||
// Asc checks if the provided error matches the specified custom error code.
|
||||
func Asc(cause error, code Code) bool {
|
||||
_, c, _, _, _, _ := Unwrapb(cause)
|
||||
_, c, _, _, _, _, _, _ := Unwrapb(cause)
|
||||
|
||||
return c.s == code.s
|
||||
}
|
||||
@@ -198,57 +351,57 @@ func Is(err error, target error) bool {
|
||||
|
||||
// WrapNotFoundf is a wrapper around Wrapf with TypeNotFound.
|
||||
func WrapNotFoundf(cause error, code Code, format string, args ...any) *base {
|
||||
return Wrapf(cause, TypeNotFound, code, format, args...)
|
||||
return Wrapf(cause, TypeNotFound, code, format, args...).WithRetry(retry{policy: RetryNever})
|
||||
}
|
||||
|
||||
// NewNotFoundf is a wrapper around Newf with TypeNotFound.
|
||||
func NewNotFoundf(code Code, format string, args ...any) *base {
|
||||
return Newf(TypeNotFound, code, format, args...)
|
||||
return Newf(TypeNotFound, code, format, args...).WithRetry(retry{policy: RetryNever})
|
||||
}
|
||||
|
||||
// WrapInternalf is a wrapper around Wrapf with TypeInternal.
|
||||
func WrapInternalf(cause error, code Code, format string, args ...any) *base {
|
||||
return Wrapf(cause, TypeInternal, code, format, args...)
|
||||
return Wrapf(cause, TypeInternal, code, format, args...).WithRetry(retry{policy: RetryNever})
|
||||
}
|
||||
|
||||
// NewInternalf is a wrapper around Newf with TypeInternal.
|
||||
func NewInternalf(code Code, format string, args ...any) *base {
|
||||
return Newf(TypeInternal, code, format, args...)
|
||||
return Newf(TypeInternal, code, format, args...).WithRetry(retry{policy: RetryNever})
|
||||
}
|
||||
|
||||
// WrapInvalidInputf is a wrapper around Wrapf with TypeInvalidInput.
|
||||
func WrapInvalidInputf(cause error, code Code, format string, args ...any) *base {
|
||||
return Wrapf(cause, TypeInvalidInput, code, format, args...)
|
||||
return Wrapf(cause, TypeInvalidInput, code, format, args...).WithRetry(retry{policy: RetryAfterFix})
|
||||
}
|
||||
|
||||
// NewInvalidInputf is a wrapper around Newf with TypeInvalidInput.
|
||||
func NewInvalidInputf(code Code, format string, args ...any) *base {
|
||||
return Newf(TypeInvalidInput, code, format, args...)
|
||||
}
|
||||
|
||||
// WrapUnexpectedf is a wrapper around Wrapf with TypeUnexpected.
|
||||
func WrapUnexpectedf(cause error, code Code, format string, args ...any) *base {
|
||||
return Wrapf(cause, TypeInvalidInput, code, format, args...)
|
||||
}
|
||||
|
||||
// NewUnexpectedf is a wrapper around Newf with TypeUnexpected.
|
||||
func NewUnexpectedf(code Code, format string, args ...any) *base {
|
||||
return Newf(TypeInvalidInput, code, format, args...)
|
||||
return Newf(TypeInvalidInput, code, format, args...).WithRetry(retry{policy: RetryAfterFix})
|
||||
}
|
||||
|
||||
// NewMethodNotAllowedf is a wrapper around Newf with TypeMethodNotAllowed.
|
||||
func NewMethodNotAllowedf(code Code, format string, args ...any) *base {
|
||||
return Newf(TypeMethodNotAllowed, code, format, args...)
|
||||
return Newf(TypeMethodNotAllowed, code, format, args...).WithRetry(retry{policy: RetryNever})
|
||||
}
|
||||
|
||||
// WrapTimeoutf is a wrapper around Wrapf with TypeTimeout.
|
||||
func WrapTimeoutf(cause error, code Code, format string, args ...any) *base {
|
||||
return Wrapf(cause, TypeTimeout, code, format, args...)
|
||||
return Wrapf(cause, TypeTimeout, code, format, args...).WithRetry(retry{policy: RetryBackoff})
|
||||
}
|
||||
|
||||
// NewTimeoutf is a wrapper around Newf with TypeTimeout.
|
||||
func NewTimeoutf(code Code, format string, args ...any) *base {
|
||||
return Newf(TypeTimeout, code, format, args...)
|
||||
return Newf(TypeTimeout, code, format, args...).WithRetry(retry{policy: RetryBackoff})
|
||||
}
|
||||
|
||||
// NewUnauthenticatedf is a wrapper around Newf with TypeUnauthenticated.
|
||||
func NewUnauthenticatedf(code Code, format string, args ...any) *base {
|
||||
return Newf(TypeUnauthenticated, code, format, args...).WithRetry(retry{policy: RetryAfterAuth})
|
||||
}
|
||||
|
||||
// NewForbiddenf is a wrapper around Newf with TypeForbidden.
|
||||
func NewForbiddenf(code Code, format string, args ...any) *base {
|
||||
return Newf(TypeForbidden, code, format, args...).WithRetry(retry{policy: RetryNever})
|
||||
}
|
||||
|
||||
// Attr returns an slog.Attr with a standardized "exception" key for the given error.
|
||||
@@ -259,6 +412,13 @@ func Attr(err error) slog.Attr {
|
||||
// TypeAttr returns an OTel attribute.KeyValue with the "error.type" semconv key
|
||||
// set to the error's type string.
|
||||
func TypeAttr(err error) attribute.KeyValue {
|
||||
t, _, _, _, _, _ := Unwrapb(err)
|
||||
t, _, _, _, _, _, _, _ := Unwrapb(err)
|
||||
return attribute.String("error.type", t.String())
|
||||
}
|
||||
|
||||
func RetryAfterOf(err error) (delay time.Duration, ok bool) {
|
||||
_, _, _, _, _, _, r, _ := Unwrapb(err)
|
||||
delay = r.after
|
||||
|
||||
return delay, r.policy == RetryAfter
|
||||
}
|
||||
|
||||
@@ -3,10 +3,30 @@ package errors
|
||||
import (
|
||||
"errors" //nolint:depguard
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFormatDuration(t *testing.T) {
|
||||
cases := []struct {
|
||||
in time.Duration
|
||||
want string
|
||||
}{
|
||||
{0, "0s"},
|
||||
{1 * time.Second, "1s"},
|
||||
{5 * time.Second, "5s"},
|
||||
{1500 * time.Millisecond, "1.5s"},
|
||||
{500 * time.Millisecond, "0.5s"},
|
||||
{1*time.Second + 3*time.Nanosecond, "1.000000003s"},
|
||||
{90 * time.Minute, "5400s"},
|
||||
{-2 * time.Second, "-2s"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
assert.Equal(t, c.want, formatDuration(c.in), "input: %v", c.in)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
typ := typ{"test-error"}
|
||||
err := New(typ, MustNewCode("code"), "test error info")
|
||||
@@ -40,7 +60,7 @@ func TestUnwrapb(t *testing.T) {
|
||||
oerr := errors.New("original error")
|
||||
berr := Wrapf(oerr, typ, MustNewCode("test_code"), "this is a base err").WithUrl("https://docs").WithAdditional("additional err")
|
||||
|
||||
atyp, acode, amessage, aerr, au, aa := Unwrapb(berr)
|
||||
atyp, acode, amessage, aerr, au, aa, _, _ := Unwrapb(berr)
|
||||
assert.Equal(t, typ, atyp)
|
||||
assert.Equal(t, "test_code", acode.String())
|
||||
assert.Equal(t, "this is a base err", amessage)
|
||||
@@ -48,7 +68,7 @@ func TestUnwrapb(t *testing.T) {
|
||||
assert.Equal(t, "https://docs", au)
|
||||
assert.Equal(t, []string{"additional err"}, aa)
|
||||
|
||||
atyp, _, _, _, _, _ = Unwrapb(oerr)
|
||||
atyp, _, _, _, _, _, _, _ = Unwrapb(oerr)
|
||||
assert.Equal(t, TypeInternal, atyp)
|
||||
}
|
||||
|
||||
@@ -59,13 +79,90 @@ func TestAttr(t *testing.T) {
|
||||
assert.Equal(t, err, attr.Value.Any())
|
||||
}
|
||||
|
||||
func TestWithSuggestions(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "test error").WithSuggestions("try this")
|
||||
_, _, _, _, _, _, _, attrs := Unwrapb(err)
|
||||
|
||||
assert.Equal(t, map[string]any{"suggestions": []string{"try this"}}, attrs)
|
||||
|
||||
// WithSuggestions replaces the existing list.
|
||||
err = err.WithSuggestions("try this instead")
|
||||
_, _, _, _, _, _, _, attrs = Unwrapb(err)
|
||||
assert.Equal(t, []string{"try this instead"}, attrs["suggestions"])
|
||||
|
||||
// AddSuggestions appends to the existing list.
|
||||
err = err.AddSuggestions("and also this")
|
||||
_, _, _, _, _, _, _, attrs = Unwrapb(err)
|
||||
assert.Equal(t, []string{"try this instead", "and also this"}, attrs["suggestions"])
|
||||
}
|
||||
|
||||
func TestWithWarnings(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "test error").WithWarnings("warn one")
|
||||
_, _, _, _, _, _, _, attrs := Unwrapb(err)
|
||||
|
||||
assert.Equal(t, map[string]any{"warnings": []string{"warn one"}}, attrs)
|
||||
|
||||
// WithWarnings replaces the existing list.
|
||||
err = err.WithWarnings("warn two")
|
||||
_, _, _, _, _, _, _, attrs = Unwrapb(err)
|
||||
assert.Equal(t, []string{"warn two"}, attrs["warnings"])
|
||||
|
||||
// AddWarnings appends to the existing list.
|
||||
err = err.AddWarnings("warn three")
|
||||
_, _, _, _, _, _, _, attrs = Unwrapb(err)
|
||||
assert.Equal(t, []string{"warn two", "warn three"}, attrs["warnings"])
|
||||
}
|
||||
|
||||
func TestWithRetryNever(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "test error").WithRetryNever()
|
||||
_, _, _, _, _, _, r, _ := Unwrapb(err)
|
||||
|
||||
assert.Equal(t, RetryNever, r.policy)
|
||||
}
|
||||
|
||||
func TestWithRetryImmediate(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "test error").WithRetryImmediate()
|
||||
_, _, _, _, _, _, r, _ := Unwrapb(err)
|
||||
|
||||
assert.Equal(t, RetryImmediate, r.policy)
|
||||
}
|
||||
|
||||
func TestWithRetryBackoff(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "test error").WithRetryBackoff()
|
||||
_, _, _, _, _, _, r, _ := Unwrapb(err)
|
||||
|
||||
assert.Equal(t, RetryBackoff, r.policy)
|
||||
}
|
||||
|
||||
func TestWithRetryAfter(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "test error").WithRetryAfter(5 * time.Microsecond)
|
||||
_, _, _, _, _, _, r, _ := Unwrapb(err)
|
||||
|
||||
assert.Equal(t, RetryAfter, r.policy)
|
||||
assert.Equal(t, 5, int(r.after.Microseconds()))
|
||||
}
|
||||
|
||||
func TestWithRetryAfterFix(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "test error").WithRetryAfterFix()
|
||||
_, _, _, _, _, _, r, _ := Unwrapb(err)
|
||||
|
||||
assert.Equal(t, RetryAfterFix, r.policy)
|
||||
}
|
||||
|
||||
func TestWithRetryAfterAuth(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "test error").WithRetryAfterAuth()
|
||||
_, _, _, _, _, _, r, _ := Unwrapb(err)
|
||||
|
||||
assert.Equal(t, RetryAfterAuth, r.policy)
|
||||
}
|
||||
|
||||
func TestWithStacktrace(t *testing.T) {
|
||||
err := New(TypeInternal, MustNewCode("test_code"), "panic").WithStacktrace("custom stack trace")
|
||||
|
||||
assert.Equal(t, "custom stack trace", err.Stacktrace())
|
||||
assert.Equal(t, "panic", err.Error())
|
||||
|
||||
typ, code, message, _, _, _ := Unwrapb(err)
|
||||
typ, code, message, _, _, _, _, _ := Unwrapb(err)
|
||||
assert.Equal(t, TypeInternal, typ)
|
||||
assert.Equal(t, "test_code", code.String())
|
||||
assert.Equal(t, "panic", message)
|
||||
|
||||
@@ -2,40 +2,90 @@ package errors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type JSON struct {
|
||||
Type string `json:"type" required:"true"`
|
||||
Code string `json:"code" required:"true"`
|
||||
Message string `json:"message" required:"true"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Errors []responseerroradditional `json:"errors,omitempty"`
|
||||
Retry *responseretryjson `json:"retry,omitempty"`
|
||||
Attrs responseattributes `json:"attrs,omitempty"`
|
||||
}
|
||||
|
||||
type responseretryjson struct {
|
||||
Policy responseretrypolicy `json:"policy"`
|
||||
// After is the retry delay in google.protobuf.Duration JSON form ("5s", "1.500s").
|
||||
// Present only when Policy == "after".
|
||||
After string `json:"after,omitempty" format:"duration" example:"5.5s" description:"Retry delay in google.protobuf.Duration JSON form. Present only when policy is \"after\"."`
|
||||
}
|
||||
|
||||
type responseretrypolicy string
|
||||
|
||||
func (r responseretrypolicy) String() string { return string(r) }
|
||||
|
||||
func (responseretrypolicy) Enum() []any {
|
||||
return []any{
|
||||
RetryNever,
|
||||
RetryImmediate,
|
||||
RetryBackoff,
|
||||
RetryAfter,
|
||||
RetryAfterFix,
|
||||
RetryAfterAuth,
|
||||
}
|
||||
}
|
||||
|
||||
type responseerroradditional struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type responseattributes map[string]any
|
||||
|
||||
func AsJSON(cause error) *JSON {
|
||||
// See if this is an instance of the base error or not
|
||||
_, c, m, _, u, a := Unwrapb(cause)
|
||||
t, c, m, _, u, a, r, attrs := Unwrapb(cause)
|
||||
|
||||
rea := make([]responseerroradditional, len(a))
|
||||
for k, v := range a {
|
||||
rea[k] = responseerroradditional{v}
|
||||
}
|
||||
|
||||
var retry *responseretryjson
|
||||
if r.policy != "" {
|
||||
retry = &responseretryjson{
|
||||
Policy: responseretrypolicy(r.policy),
|
||||
}
|
||||
if r.policy == RetryAfter {
|
||||
retry.After = formatDuration(r.after)
|
||||
}
|
||||
}
|
||||
|
||||
if len(attrs) == 0 {
|
||||
attrs = nil
|
||||
}
|
||||
|
||||
return &JSON{
|
||||
Type: t.String(),
|
||||
Code: c.String(),
|
||||
Message: m,
|
||||
Url: u,
|
||||
Errors: rea,
|
||||
Retry: retry,
|
||||
Attrs: attrs,
|
||||
}
|
||||
}
|
||||
|
||||
// AsURLValues is only used for SSO, ideally this method shouldn't be here.
|
||||
// TODO(pandey): Update the method or the comment.
|
||||
func AsURLValues(cause error) url.Values {
|
||||
// See if this is an instance of the base error or not
|
||||
_, c, m, _, u, a := Unwrapb(cause)
|
||||
t, c, m, _, u, a, _, _ := Unwrapb(cause)
|
||||
|
||||
rea := make([]responseerroradditional, len(a))
|
||||
for k, v := range a {
|
||||
@@ -45,6 +95,7 @@ func AsURLValues(cause error) url.Values {
|
||||
errors, err := json.Marshal(rea)
|
||||
if err != nil {
|
||||
return url.Values{
|
||||
"type": {t.String()},
|
||||
"code": {c.String()},
|
||||
"message": {m},
|
||||
"url": {u},
|
||||
@@ -52,9 +103,34 @@ func AsURLValues(cause error) url.Values {
|
||||
}
|
||||
|
||||
return url.Values{
|
||||
"type": {t.String()},
|
||||
"code": {c.String()},
|
||||
"message": {m},
|
||||
"url": {u},
|
||||
"errors": {string(errors)},
|
||||
}
|
||||
}
|
||||
|
||||
// formatDuration serializes a time.Duration as a google.protobuf.Duration JSON value
|
||||
// (https://protobuf.dev/reference/protobuf/google.protobuf/#duration): "<seconds>[.<fractional>]s".
|
||||
// Trailing zeros in the fractional part are stripped.
|
||||
func formatDuration(d time.Duration) string {
|
||||
if d == 0 {
|
||||
return "0s"
|
||||
}
|
||||
negative := d < 0
|
||||
if negative {
|
||||
d = -d
|
||||
}
|
||||
sec := d / time.Second
|
||||
nano := d % time.Second
|
||||
out := strconv.FormatInt(int64(sec), 10)
|
||||
if nano != 0 {
|
||||
frac := strings.TrimRight(fmt.Sprintf("%09d", nano), "0")
|
||||
out = out + "." + frac
|
||||
}
|
||||
if negative {
|
||||
out = "-" + out
|
||||
}
|
||||
return out + "s"
|
||||
}
|
||||
|
||||
19
pkg/errors/retry.go
Normal file
19
pkg/errors/retry.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
RetryNever string = "never" // retry with the same inputs cannot succeed.
|
||||
RetryImmediate string = "immediate" // retry without waiting.
|
||||
RetryBackoff string = "backoff" // caller picks its own backoff schedule.
|
||||
RetryAfter string = "after" // honor Retry.After exactly (the producer knows the wait).
|
||||
RetryAfterFix string = "after_fix" // retry pointless until the caller fixes the request.
|
||||
RetryAfterAuth string = "after_auth" // retry pointless until the caller re-authenticates.
|
||||
)
|
||||
|
||||
type retry struct {
|
||||
policy string
|
||||
after time.Duration
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
package errors
|
||||
|
||||
var (
|
||||
TypeInvalidInput typ = typ{"invalid-input"}
|
||||
TypeInternal = typ{"internal"}
|
||||
TypeUnsupported = typ{"unsupported"}
|
||||
TypeNotFound = typ{"not-found"}
|
||||
TypeMethodNotAllowed = typ{"method-not-allowed"}
|
||||
TypeAlreadyExists = typ{"already-exists"}
|
||||
TypeUnauthenticated = typ{"unauthenticated"}
|
||||
TypeForbidden = typ{"forbidden"}
|
||||
TypeCanceled = typ{"canceled"}
|
||||
TypeTimeout = typ{"timeout"}
|
||||
TypeUnexpected = typ{"unexpected"} // Generic mismatch of expectations
|
||||
TypeFatal = typ{"fatal"} // Unrecoverable failure (e.g. panic)
|
||||
TypeLicenseUnavailable = typ{"license-unavailable"}
|
||||
TypeTooManyRequests = typ{"too-many-requests"}
|
||||
TypeInvalidInput typ = typ{"invalid-input"}
|
||||
TypeInternal = typ{"internal"}
|
||||
TypeUnsupported = typ{"unsupported"}
|
||||
TypeNotFound = typ{"not-found"}
|
||||
TypeMethodNotAllowed = typ{"method-not-allowed"}
|
||||
TypeAlreadyExists = typ{"already-exists"}
|
||||
TypeUnauthenticated = typ{"unauthenticated"}
|
||||
TypeForbidden = typ{"forbidden"}
|
||||
TypeCanceled = typ{"canceled"}
|
||||
TypeTimeout = typ{"timeout"}
|
||||
// TypeUnexpected = typ{"unexpected"} // There's nothing unexpected in the world, just things we don't understand yet
|
||||
TypeFatal = typ{"fatal"} // Unrecoverable failure (e.g. panic)
|
||||
TypeLicenseUnavailable = typ{"license-unavailable"}
|
||||
TypeTooManyRequests = typ{"too-many-requests"}
|
||||
)
|
||||
|
||||
// Defines custom error types.
|
||||
|
||||
@@ -58,7 +58,7 @@ func TestJSONBinding_BindBodyErrors(t *testing.T) {
|
||||
err := JSON.BindBody(strings.NewReader(testCase.body), testCase.obj, testCase.opts...)
|
||||
assert.Error(t, err)
|
||||
|
||||
typ, c, m, _, _, a := errors.Unwrapb(err)
|
||||
typ, c, m, _, _, a, _, _ := errors.Unwrapb(err)
|
||||
assert.Equal(t, errors.TypeInvalidInput, typ)
|
||||
assert.Equal(t, testCase.code, c)
|
||||
assert.Equal(t, testCase.message, m)
|
||||
|
||||
@@ -101,7 +101,7 @@ func TestRecovery(t *testing.T) {
|
||||
err := extractException(t, records[0])
|
||||
require.NotNil(t, err)
|
||||
|
||||
typ, _, message, _, _, _ := errors.Unwrapb(err)
|
||||
typ, _, message, _, _, _, _, _ := errors.Unwrapb(err)
|
||||
assert.Equal(t, errors.TypeFatal, typ)
|
||||
assert.Equal(t, tc.wantMessage, message)
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package render
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
@@ -86,7 +88,7 @@ func ErrorTypeFromStatusCode(statusCode int) string {
|
||||
|
||||
func Error(rw http.ResponseWriter, cause error) {
|
||||
// Derive the http code from the error type
|
||||
t, _, _, _, _, _ := errors.Unwrapb(cause)
|
||||
t, _, _, _, _, _, _, _ := errors.Unwrapb(cause)
|
||||
|
||||
httpCode := http.StatusInternalServerError
|
||||
switch t {
|
||||
@@ -121,6 +123,13 @@ func Error(rw http.ResponseWriter, cause error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Retry-After carries the explicit delay declared via
|
||||
// errors.WithRetryAfter. Set it before WriteHeader so headers go on the wire.
|
||||
if d, ok := errors.RetryAfterOf(cause); ok {
|
||||
seconds := max(int64((d+time.Second-1)/time.Second), 0)
|
||||
rw.Header().Set("Retry-After", strconv.FormatInt(seconds, 10))
|
||||
}
|
||||
|
||||
rw.WriteHeader(httpCode)
|
||||
_, _ = rw.Write(body)
|
||||
}
|
||||
|
||||
@@ -97,13 +97,13 @@ func TestError(t *testing.T) {
|
||||
name: "AlreadyExists",
|
||||
statusCode: http.StatusConflict,
|
||||
err: errors.New(errors.TypeAlreadyExists, errors.MustNewCode("already_exists"), "already exists").WithUrl("https://already_exists"),
|
||||
expected: []byte(`{"status":"error","error":{"code":"already_exists","message":"already exists","url":"https://already_exists"}}`),
|
||||
expected: []byte(`{"status":"error","error":{"type":"already-exists","code":"already_exists","message":"already exists","url":"https://already_exists"}}`),
|
||||
},
|
||||
"/unauthenticated": {
|
||||
name: "Unauthenticated",
|
||||
statusCode: http.StatusUnauthorized,
|
||||
err: errors.New(errors.TypeUnauthenticated, errors.MustNewCode("not_allowed"), "not allowed").WithUrl("https://unauthenticated").WithAdditional("a1", "a2"),
|
||||
expected: []byte(`{"status":"error","error":{"code":"not_allowed","message":"not allowed","url":"https://unauthenticated","errors":[{"message":"a1"},{"message":"a2"}]}}`),
|
||||
expected: []byte(`{"status":"error","error":{"type":"unauthenticated","code":"not_allowed","message":"not allowed","url":"https://unauthenticated","errors":[{"message":"a1"},{"message":"a2"}]}}`),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func (h *exception) Wrap(next LogHandler) LogHandler {
|
||||
return next.Handle(ctx, record)
|
||||
}
|
||||
|
||||
t, c, m, _, _, _ := errors.Unwrapb(foundErr)
|
||||
t, c, m, _, _, _, _, _ := errors.Unwrapb(foundErr)
|
||||
|
||||
newRecord.AddAttrs(
|
||||
slog.String("exception.type", t.String()),
|
||||
|
||||
@@ -202,15 +202,15 @@ func (handler *handler) exportRawDataJSONL(rowChan <-chan *qbtypes.RawRow, errCh
|
||||
}
|
||||
jsonBytes, err := json.Marshal(row.Data)
|
||||
if err != nil {
|
||||
return false, errors.NewUnexpectedf(errors.CodeInternal, "error marshaling JSON: %s", err)
|
||||
return false, errors.NewInternalf(errors.CodeInternal, "error marshaling JSON: %s", err)
|
||||
}
|
||||
totalBytes += uint64(len(jsonBytes)) + 1
|
||||
|
||||
if _, err := writer.Write(jsonBytes); err != nil {
|
||||
return false, errors.NewUnexpectedf(errors.CodeInternal, "error writing JSON: %s", err)
|
||||
return false, errors.NewInternalf(errors.CodeInternal, "error writing JSON: %s", err)
|
||||
}
|
||||
if _, err := writer.Write([]byte("\n")); err != nil {
|
||||
return false, errors.NewUnexpectedf(errors.CodeInternal, "error writing JSON newline: %s", err)
|
||||
return false, errors.NewInternalf(errors.CodeInternal, "error writing JSON newline: %s", err)
|
||||
}
|
||||
|
||||
if totalBytes > MaxExportBytesLimit {
|
||||
|
||||
@@ -74,7 +74,7 @@ func (module *getter) ListDeprecatedUsersByOrgID(ctx context.Context, orgID valu
|
||||
roleNames := userIDToRoleNames[user.ID]
|
||||
|
||||
if len(roleNames) == 0 {
|
||||
return nil, errors.Newf(errors.TypeUnexpected, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found for user: %s", user.ID.String())
|
||||
return nil, errors.Newf(errors.TypeInternal, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found for user: %s", user.ID.String())
|
||||
}
|
||||
|
||||
role := authtypes.SigNozManagedRoleToExistingLegacyRole[roleNames[0]]
|
||||
@@ -113,11 +113,11 @@ func (module *getter) GetDeprecatedUserByOrgIDAndID(ctx context.Context, orgID v
|
||||
}
|
||||
|
||||
if len(userRoles) == 0 {
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found")
|
||||
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found")
|
||||
}
|
||||
|
||||
if userRoles[0].Role == nil {
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
}
|
||||
|
||||
role := authtypes.SigNozManagedRoleToExistingLegacyRole[userRoles[0].Role.Name]
|
||||
@@ -141,11 +141,11 @@ func (module *getter) Get(ctx context.Context, id valuer.UUID) (*types.Deprecate
|
||||
}
|
||||
|
||||
if len(userRoles) == 0 {
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found")
|
||||
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeUserRolesNotFound, "no user roles entries found")
|
||||
}
|
||||
|
||||
if userRoles[0].Role == nil {
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
}
|
||||
|
||||
role := authtypes.SigNozManagedRoleToExistingLegacyRole[userRoles[0].Role.Name]
|
||||
@@ -211,7 +211,7 @@ func (module *getter) GetRolesByUserID(ctx context.Context, userID valuer.UUID)
|
||||
|
||||
for _, ur := range userRoles {
|
||||
if ur.Role == nil {
|
||||
return nil, errors.New(errors.TypeUnexpected, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
return nil, errors.New(errors.TypeInternal, authtypes.ErrCodeRoleNotFound, "role not found for user role entry")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ type ApiResponse struct {
|
||||
// toApiError translates a pkg/errors typed error into the legacy
|
||||
// model.ApiError to preserve the v1 JSON response shape.
|
||||
func toApiError(err error) *model.ApiError {
|
||||
t, _, _, _, _, _ := errors.Unwrapb(err)
|
||||
t, _, _, _, _, _, _, _ := errors.Unwrapb(err)
|
||||
|
||||
var typ model.ErrorType
|
||||
switch t {
|
||||
|
||||
@@ -216,7 +216,7 @@ func getOperators(ops []pipelinetypes.PipelineOperator) ([]pipelinetypes.Pipelin
|
||||
|
||||
func processSeverityParser(operator *pipelinetypes.PipelineOperator) error {
|
||||
if operator.Type != "severity_parser" {
|
||||
return errors.NewUnexpectedf(CodeInvalidOperatorType, "operator type received %s", operator.Type)
|
||||
return errors.NewInternalf(CodeInvalidOperatorType, "operator type received %s", operator.Type)
|
||||
}
|
||||
|
||||
parseFromNotNilCheck, err := fieldNotNilCheck(operator.ParseFrom)
|
||||
@@ -236,7 +236,7 @@ func processSeverityParser(operator *pipelinetypes.PipelineOperator) error {
|
||||
// processJSONParser converts simple JSON parser operator into multiple operators for JSONMapping of default variables
|
||||
func processJSONParser(parent *pipelinetypes.PipelineOperator) ([]pipelinetypes.PipelineOperator, error) {
|
||||
if parent.Type != "json_parser" {
|
||||
return nil, errors.NewUnexpectedf(CodeInvalidOperatorType, "operator type received %s", parent.Type)
|
||||
return nil, errors.NewInternalf(CodeInvalidOperatorType, "operator type received %s", parent.Type)
|
||||
}
|
||||
|
||||
parseFromNotNilCheck, err := fieldNotNilCheck(parent.ParseFrom)
|
||||
|
||||
@@ -40,11 +40,11 @@ func runLogsAndTracesTests(t *testing.T, tests []logsAndTracesTestCase) {
|
||||
if tt.wantErr {
|
||||
require.Error(t, errLogs)
|
||||
assert.ErrorContains(t, errLogs, tt.wantErrMsg)
|
||||
_, _, _, _, _, additionalLogs := errors.Unwrapb(errLogs)
|
||||
_, _, _, _, _, additionalLogs, _, _ := errors.Unwrapb(errLogs)
|
||||
assert.Equal(t, tt.wantAdditional, additionalLogs)
|
||||
require.Error(t, errTraces)
|
||||
assert.ErrorContains(t, errTraces, tt.wantErrMsg)
|
||||
_, _, _, _, _, additionalTraces := errors.Unwrapb(errTraces)
|
||||
_, _, _, _, _, additionalTraces, _, _ := errors.Unwrapb(errTraces)
|
||||
assert.Equal(t, tt.wantAdditional, additionalTraces)
|
||||
} else {
|
||||
require.NoError(t, errLogs)
|
||||
@@ -1039,7 +1039,7 @@ func TestRewriteForMetrics(t *testing.T) {
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
assert.ErrorContains(t, err, tt.wantErrMsg)
|
||||
_, _, _, _, _, additional := errors.Unwrapb(err)
|
||||
_, _, _, _, _, additional, _, _ := errors.Unwrapb(err)
|
||||
assert.Equal(t, tt.wantAdditional, additional)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -2415,7 +2415,7 @@ func TestFilterExprLogs(t *testing.T) {
|
||||
require.Equal(t, tc.expectedArgs, args)
|
||||
} else {
|
||||
require.Error(t, err, "Expected error for query: %s", tc.query)
|
||||
_, _, _, _, _, a := errors.Unwrapb(err)
|
||||
_, _, _, _, _, a, _, _ := errors.Unwrapb(err)
|
||||
contains := false
|
||||
for _, warn := range a {
|
||||
if strings.Contains(warn, tc.expectedErrorContains) {
|
||||
@@ -2536,7 +2536,7 @@ func TestFilterExprLogsConflictNegation(t *testing.T) {
|
||||
require.Equal(t, tc.expectedArgs, args)
|
||||
} else {
|
||||
require.Error(t, err, "Expected error for query: %s", tc.query)
|
||||
_, _, _, _, _, a := errors.Unwrapb(err)
|
||||
_, _, _, _, _, a, _, _ := errors.Unwrapb(err)
|
||||
contains := false
|
||||
for _, warn := range a {
|
||||
if strings.Contains(warn, tc.expectedErrorContains) {
|
||||
|
||||
@@ -1025,7 +1025,7 @@ func TestStmtBuilderBodyField(t *testing.T) {
|
||||
require.Contains(t, err.Error(), c.expectedErr.Error())
|
||||
} else {
|
||||
if err != nil {
|
||||
_, _, _, _, _, add := errors.Unwrapb(err)
|
||||
_, _, _, _, _, add, _, _ := errors.Unwrapb(err)
|
||||
t.Logf("error additionals: %v", add)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
@@ -1124,7 +1124,7 @@ func TestStmtBuilderBodyFullTextSearch(t *testing.T) {
|
||||
require.Contains(t, err.Error(), c.expectedErr.Error())
|
||||
} else {
|
||||
if err != nil {
|
||||
_, _, _, _, _, add := errors.Unwrapb(err)
|
||||
_, _, _, _, _, add, _, _ := errors.Unwrapb(err)
|
||||
t.Logf("error additionals: %v", add)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -29,7 +29,7 @@ func NewContextWithClaims(ctx context.Context, claims Claims) context.Context {
|
||||
func ClaimsFromContext(ctx context.Context) (Claims, error) {
|
||||
claims, ok := ctx.Value(claimsKey{}).(Claims)
|
||||
if !ok {
|
||||
return Claims{}, errors.New(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")
|
||||
return Claims{}, errors.NewUnauthenticatedf(errors.CodeUnauthenticated, "unauthenticated")
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
@@ -42,7 +42,7 @@ func NewContextWithAccessToken(ctx context.Context, accessToken string) context.
|
||||
func AccessTokenFromContext(ctx context.Context) (string, error) {
|
||||
accessToken, ok := ctx.Value(accessTokenKey{}).(string)
|
||||
if !ok {
|
||||
return "", errors.New(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")
|
||||
return "", errors.NewUnauthenticatedf(errors.CodeUnauthenticated, "unauthenticated")
|
||||
}
|
||||
|
||||
return accessToken, nil
|
||||
@@ -55,7 +55,7 @@ func NewContextWithAPIKey(ctx context.Context, apiKey string) context.Context {
|
||||
func APIKeyFromContext(ctx context.Context) (string, error) {
|
||||
apiKey, ok := ctx.Value(apiKeyKey{}).(string)
|
||||
if !ok {
|
||||
return "", errors.New(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")
|
||||
return "", errors.NewUnauthenticatedf(errors.CodeUnauthenticated, "unauthenticated")
|
||||
}
|
||||
|
||||
return apiKey, nil
|
||||
@@ -77,7 +77,7 @@ func (c *Claims) IsSelfAccess(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New(errors.TypeForbidden, errors.CodeForbidden, "only the user/admin can access their own resource")
|
||||
return errors.NewForbiddenf(errors.CodeForbidden, "only the user/admin can access their own resource")
|
||||
}
|
||||
|
||||
func (c *Claims) IdentityID() string {
|
||||
|
||||
@@ -117,7 +117,7 @@ func wrapUnmarshalError(err error, errorFormat string, args ...interface{}) erro
|
||||
}
|
||||
|
||||
// If it's already one of our wrapped errors with additional context, return as-is
|
||||
_, _, _, _, _, additionals := errors.Unwrapb(err)
|
||||
_, _, _, _, _, additionals, _, _ := errors.Unwrapb(err)
|
||||
if len(additionals) > 0 {
|
||||
return err
|
||||
}
|
||||
@@ -144,7 +144,7 @@ func wrapValidationError(err error, contextIdentifier string, errorFormat string
|
||||
}
|
||||
|
||||
// Extract the underlying error details
|
||||
_, _, innerMsg, _, _, additionals := errors.Unwrapb(err)
|
||||
_, _, innerMsg, _, _, additionals, _, _ := errors.Unwrapb(err)
|
||||
|
||||
// Create a new error with the provided format
|
||||
newErr := errors.NewInvalidInputf(
|
||||
|
||||
@@ -130,7 +130,7 @@ func TestQueryRangeRequest_UnmarshalJSON_ErrorMessages(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), tt.wantErrMsg)
|
||||
|
||||
// Check if it's an error from our package using Unwrapb
|
||||
_, _, _, _, _, additionals := errors.Unwrapb(err)
|
||||
_, _, _, _, _, additionals, _, _ := errors.Unwrapb(err)
|
||||
|
||||
// Check additional hints if we have any
|
||||
if len(additionals) > 0 {
|
||||
|
||||
Reference in New Issue
Block a user