mirror of
https://github.com/prometheus/prometheus.git
synced 2025-08-06 06:07:11 +02:00
make annotations use an interface
Signed-off-by: Jeanette Tan <jeanette.tan@grafana.com>
This commit is contained in:
parent
19cc2472a5
commit
023c062588
@ -3471,7 +3471,7 @@ func handleVectorBinopError(err error, e *parser.BinaryExpr) annotations.Annotat
|
|||||||
metricName := ""
|
metricName := ""
|
||||||
pos := e.PositionRange()
|
pos := e.PositionRange()
|
||||||
if errors.Is(err, annotations.PromQLInfo) || errors.Is(err, annotations.PromQLWarning) {
|
if errors.Is(err, annotations.PromQLInfo) || errors.Is(err, annotations.PromQLWarning) {
|
||||||
return annotations.New().Add(err)
|
return annotations.New().AddRaw(err)
|
||||||
}
|
}
|
||||||
if errors.Is(err, histogram.ErrHistogramsIncompatibleSchema) {
|
if errors.Is(err, histogram.ErrHistogramsIncompatibleSchema) {
|
||||||
return annotations.New().Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, pos))
|
return annotations.New().Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, pos))
|
||||||
|
@ -65,7 +65,7 @@ func TestRecoverEvaluatorErrorWithWarnings(t *testing.T) {
|
|||||||
var err error
|
var err error
|
||||||
var ws annotations.Annotations
|
var ws annotations.Annotations
|
||||||
|
|
||||||
warnings := annotations.New().Add(errors.New("custom warning"))
|
warnings := annotations.New().AddRaw(errors.New("custom warning"))
|
||||||
e := errWithWarnings{
|
e := errWithWarnings{
|
||||||
err: errors.New("custom error"),
|
err: errors.New("custom error"),
|
||||||
warnings: warnings,
|
warnings: warnings,
|
||||||
|
@ -1540,7 +1540,7 @@ func TestMergeQuerierWithSecondaries_ErrorHandling(t *testing.T) {
|
|||||||
&mockQuerier{resp: []string{"b"}, warnings: nil, err: errStorage},
|
&mockQuerier{resp: []string{"b"}, warnings: nil, err: errStorage},
|
||||||
},
|
},
|
||||||
expectedLabels: []string{},
|
expectedLabels: []string{},
|
||||||
expectedWarnings: annotations.New().Add(errStorage),
|
expectedWarnings: annotations.New().AddRaw(errStorage),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "nil primary querier with two failed secondaries",
|
name: "nil primary querier with two failed secondaries",
|
||||||
@ -1550,7 +1550,7 @@ func TestMergeQuerierWithSecondaries_ErrorHandling(t *testing.T) {
|
|||||||
&mockQuerier{resp: []string{"c"}, warnings: nil, err: errStorage},
|
&mockQuerier{resp: []string{"c"}, warnings: nil, err: errStorage},
|
||||||
},
|
},
|
||||||
expectedLabels: []string{},
|
expectedLabels: []string{},
|
||||||
expectedWarnings: annotations.New().Add(errStorage),
|
expectedWarnings: annotations.New().AddRaw(errStorage),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one successful primary querier with failed secondaries",
|
name: "one successful primary querier with failed secondaries",
|
||||||
@ -1565,30 +1565,30 @@ func TestMergeQuerierWithSecondaries_ErrorHandling(t *testing.T) {
|
|||||||
labels.FromStrings("test", "a"),
|
labels.FromStrings("test", "a"),
|
||||||
},
|
},
|
||||||
expectedLabels: []string{"a"},
|
expectedLabels: []string{"a"},
|
||||||
expectedWarnings: annotations.New().Add(errStorage),
|
expectedWarnings: annotations.New().AddRaw(errStorage),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "successful queriers with warnings",
|
name: "successful queriers with warnings",
|
||||||
primaries: []Querier{
|
primaries: []Querier{
|
||||||
&mockQuerier{resp: []string{"a"}, warnings: annotations.New().Add(warnStorage), err: nil},
|
&mockQuerier{resp: []string{"a"}, warnings: annotations.New().AddRaw(warnStorage), err: nil},
|
||||||
},
|
},
|
||||||
secondaries: []Querier{
|
secondaries: []Querier{
|
||||||
&mockQuerier{resp: []string{"b"}, warnings: annotations.New().Add(warnStorage), err: nil},
|
&mockQuerier{resp: []string{"b"}, warnings: annotations.New().AddRaw(warnStorage), err: nil},
|
||||||
},
|
},
|
||||||
expectedSelectsSeries: []labels.Labels{
|
expectedSelectsSeries: []labels.Labels{
|
||||||
labels.FromStrings("test", "a"),
|
labels.FromStrings("test", "a"),
|
||||||
labels.FromStrings("test", "b"),
|
labels.FromStrings("test", "b"),
|
||||||
},
|
},
|
||||||
expectedLabels: []string{"a", "b"},
|
expectedLabels: []string{"a", "b"},
|
||||||
expectedWarnings: annotations.New().Add(warnStorage),
|
expectedWarnings: annotations.New().AddRaw(warnStorage),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "successful queriers with limit",
|
name: "successful queriers with limit",
|
||||||
primaries: []Querier{
|
primaries: []Querier{
|
||||||
&mockQuerier{resp: []string{"a", "d"}, warnings: annotations.New().Add(warnStorage), err: nil},
|
&mockQuerier{resp: []string{"a", "d"}, warnings: annotations.New().AddRaw(warnStorage), err: nil},
|
||||||
},
|
},
|
||||||
secondaries: []Querier{
|
secondaries: []Querier{
|
||||||
&mockQuerier{resp: []string{"b", "c"}, warnings: annotations.New().Add(warnStorage), err: nil},
|
&mockQuerier{resp: []string{"b", "c"}, warnings: annotations.New().AddRaw(warnStorage), err: nil},
|
||||||
},
|
},
|
||||||
limit: 2,
|
limit: 2,
|
||||||
expectedSelectsSeries: []labels.Labels{
|
expectedSelectsSeries: []labels.Labels{
|
||||||
@ -1596,7 +1596,7 @@ func TestMergeQuerierWithSecondaries_ErrorHandling(t *testing.T) {
|
|||||||
labels.FromStrings("test", "b"),
|
labels.FromStrings("test", "b"),
|
||||||
},
|
},
|
||||||
expectedLabels: []string{"a", "b"},
|
expectedLabels: []string{"a", "b"},
|
||||||
expectedWarnings: annotations.New().Add(warnStorage),
|
expectedWarnings: annotations.New().AddRaw(warnStorage),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
var labelHints *LabelHints
|
var labelHints *LabelHints
|
||||||
|
@ -127,7 +127,7 @@ func exponentialToNativeHistogram(p pmetric.ExponentialHistogramDataPoint) (prom
|
|||||||
}
|
}
|
||||||
h.Count = &prompb.Histogram_CountInt{CountInt: p.Count()}
|
h.Count = &prompb.Histogram_CountInt{CountInt: p.Count()}
|
||||||
if p.Count() == 0 && h.Sum != 0 {
|
if p.Count() == 0 && h.Sum != 0 {
|
||||||
annots.Add(fmt.Errorf("exponential histogram data point has zero count, but non-zero sum: %f", h.Sum))
|
annots.AddRaw(fmt.Errorf("exponential histogram data point has zero count, but non-zero sum: %f", h.Sum))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return h, annots, nil
|
return h, annots, nil
|
||||||
|
@ -52,7 +52,7 @@ func newSecondaryQuerierFromChunk(cq ChunkQuerier) genericQuerier {
|
|||||||
func (s *secondaryQuerier) LabelValues(ctx context.Context, name string, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (s *secondaryQuerier) LabelValues(ctx context.Context, name string, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
vals, w, err := s.genericQuerier.LabelValues(ctx, name, hints, matchers...)
|
vals, w, err := s.genericQuerier.LabelValues(ctx, name, hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, w.Add(err), nil
|
return nil, w.AddRaw(err), nil
|
||||||
}
|
}
|
||||||
return vals, w, nil
|
return vals, w, nil
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ func (s *secondaryQuerier) LabelValues(ctx context.Context, name string, hints *
|
|||||||
func (s *secondaryQuerier) LabelNames(ctx context.Context, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
func (s *secondaryQuerier) LabelNames(ctx context.Context, hints *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) {
|
||||||
names, w, err := s.genericQuerier.LabelNames(ctx, hints, matchers...)
|
names, w, err := s.genericQuerier.LabelNames(ctx, hints, matchers...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, w.Add(err), nil
|
return nil, w.AddRaw(err), nil
|
||||||
}
|
}
|
||||||
return names, w, nil
|
return names, w, nil
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ func (s *secondaryQuerier) Select(ctx context.Context, sortSeries bool, hints *S
|
|||||||
if err := set.Err(); err != nil {
|
if err := set.Err(); err != nil {
|
||||||
// One of the sets failed, ensure current one returning errors as warnings, and rest of the sets return nothing.
|
// One of the sets failed, ensure current one returning errors as warnings, and rest of the sets return nothing.
|
||||||
// (All or nothing logic).
|
// (All or nothing logic).
|
||||||
s.asyncSets[curr] = warningsOnlySeriesSet(ws.Add(err))
|
s.asyncSets[curr] = warningsOnlySeriesSet(ws.AddRaw(err))
|
||||||
for i := range s.asyncSets {
|
for i := range s.asyncSets {
|
||||||
if curr == i {
|
if curr == i {
|
||||||
continue
|
continue
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
// Each individual annotation is modeled by a Go error.
|
// Each individual annotation is modeled by a Go error.
|
||||||
// They are deduplicated based on the string returned by error.Error().
|
// They are deduplicated based on the string returned by error.Error().
|
||||||
// The zero value is usable without further initialization, see New().
|
// The zero value is usable without further initialization, see New().
|
||||||
type Annotations map[string]error
|
type Annotations map[string]annoErr
|
||||||
|
|
||||||
// New returns new Annotations ready to use. Note that the zero value of
|
// New returns new Annotations ready to use. Note that the zero value of
|
||||||
// Annotations is also fully usable, but using this method is often more
|
// Annotations is also fully usable, but using this method is often more
|
||||||
@ -38,14 +38,24 @@ func New() *Annotations {
|
|||||||
|
|
||||||
// Add adds an annotation (modeled as a Go error) in-place and returns the
|
// Add adds an annotation (modeled as a Go error) in-place and returns the
|
||||||
// modified Annotations for convenience.
|
// modified Annotations for convenience.
|
||||||
func (a *Annotations) Add(err error) Annotations {
|
func (a *Annotations) Add(err annoErr) Annotations {
|
||||||
if *a == nil {
|
if *a == nil {
|
||||||
*a = Annotations{}
|
*a = Annotations{}
|
||||||
}
|
}
|
||||||
|
prevErr, exists := (*a)[err.Error()]
|
||||||
|
if exists {
|
||||||
|
err = err.merge(prevErr)
|
||||||
|
}
|
||||||
(*a)[err.Error()] = err
|
(*a)[err.Error()] = err
|
||||||
return *a
|
return *a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddRaw is like Add, but a convenience wrapper for adding raw errors instead of annoErrs
|
||||||
|
// that have query and position information and possibly a custom merge function.
|
||||||
|
func (a *Annotations) AddRaw(err error) Annotations {
|
||||||
|
return a.Add(&rawErr{Err: err})
|
||||||
|
}
|
||||||
|
|
||||||
// Merge adds the contents of the second annotation to the first, modifying
|
// Merge adds the contents of the second annotation to the first, modifying
|
||||||
// the first in-place, and returns the merged first Annotation for convenience.
|
// the first in-place, and returns the merged first Annotation for convenience.
|
||||||
func (a *Annotations) Merge(aa Annotations) Annotations {
|
func (a *Annotations) Merge(aa Annotations) Annotations {
|
||||||
@ -56,6 +66,10 @@ func (a *Annotations) Merge(aa Annotations) Annotations {
|
|||||||
*a = Annotations{}
|
*a = Annotations{}
|
||||||
}
|
}
|
||||||
for key, val := range aa {
|
for key, val := range aa {
|
||||||
|
prevVal, exists := (*a)[key]
|
||||||
|
if exists {
|
||||||
|
val = val.merge(prevVal)
|
||||||
|
}
|
||||||
(*a)[key] = val
|
(*a)[key] = val
|
||||||
}
|
}
|
||||||
return *a
|
return *a
|
||||||
@ -82,11 +96,7 @@ func (a Annotations) AsStrings(query string, maxWarnings, maxInfos int) (warning
|
|||||||
warnSkipped := 0
|
warnSkipped := 0
|
||||||
infoSkipped := 0
|
infoSkipped := 0
|
||||||
for _, err := range a {
|
for _, err := range a {
|
||||||
var anErr annoErr
|
err.setQuery(query)
|
||||||
if errors.As(err, &anErr) {
|
|
||||||
anErr.Query = query
|
|
||||||
err = anErr
|
|
||||||
}
|
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, PromQLInfo):
|
case errors.Is(err, PromQLInfo):
|
||||||
if maxInfos == 0 || len(infos) < maxInfos {
|
if maxInfos == 0 || len(infos) < maxInfos {
|
||||||
@ -150,27 +160,65 @@ var (
|
|||||||
HistogramIgnoredInAggregationInfo = fmt.Errorf("%w: ignored histogram in", PromQLInfo)
|
HistogramIgnoredInAggregationInfo = fmt.Errorf("%w: ignored histogram in", PromQLInfo)
|
||||||
)
|
)
|
||||||
|
|
||||||
type annoErr struct {
|
type annoErr interface {
|
||||||
|
error
|
||||||
|
// We can define custom merge functions to merge annoErrs with the same raw error string.
|
||||||
|
merge(annoErr) annoErr
|
||||||
|
// Necessary when we want to show position info. Also, this is only called at the end when we call
|
||||||
|
// AsStrings(), so before that we deduplicate based on the raw error string when query is empty,
|
||||||
|
// and the full error string with details will only be shown in the end when query is set.
|
||||||
|
setQuery(string)
|
||||||
|
// Necessary so we can use errors.Is() to disambiguate between warning and info.
|
||||||
|
Unwrap() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type rawErr struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *rawErr) merge(_ annoErr) annoErr {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *rawErr) setQuery(query string) {}
|
||||||
|
|
||||||
|
func (e *rawErr) Error() string {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *rawErr) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
type genericAnnoErr struct {
|
||||||
PositionRange posrange.PositionRange
|
PositionRange posrange.PositionRange
|
||||||
Err error
|
Err error
|
||||||
Query string
|
Query string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e annoErr) Error() string {
|
func (e *genericAnnoErr) merge(_ annoErr) annoErr {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *genericAnnoErr) setQuery(query string) {
|
||||||
|
e.Query = query
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *genericAnnoErr) Error() string {
|
||||||
if e.Query == "" {
|
if e.Query == "" {
|
||||||
return e.Err.Error()
|
return e.Err.Error()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s (%s)", e.Err, e.PositionRange.StartPosInput(e.Query, 0))
|
return fmt.Sprintf("%s (%s)", e.Err, e.PositionRange.StartPosInput(e.Query, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e annoErr) Unwrap() error {
|
func (e *genericAnnoErr) Unwrap() error {
|
||||||
return e.Err
|
return e.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInvalidQuantileWarning is used when the user specifies an invalid quantile
|
// NewInvalidQuantileWarning is used when the user specifies an invalid quantile
|
||||||
// value, i.e. a float that is outside the range [0, 1] or NaN.
|
// value, i.e. a float that is outside the range [0, 1] or NaN.
|
||||||
func NewInvalidQuantileWarning(q float64, pos posrange.PositionRange) error {
|
func NewInvalidQuantileWarning(q float64, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w, got %g", InvalidQuantileWarning, q),
|
Err: fmt.Errorf("%w, got %g", InvalidQuantileWarning, q),
|
||||||
}
|
}
|
||||||
@ -178,8 +226,8 @@ func NewInvalidQuantileWarning(q float64, pos posrange.PositionRange) error {
|
|||||||
|
|
||||||
// NewInvalidRatioWarning is used when the user specifies an invalid ratio
|
// NewInvalidRatioWarning is used when the user specifies an invalid ratio
|
||||||
// value, i.e. a float that is outside the range [-1, 1] or NaN.
|
// value, i.e. a float that is outside the range [-1, 1] or NaN.
|
||||||
func NewInvalidRatioWarning(q, to float64, pos posrange.PositionRange) error {
|
func NewInvalidRatioWarning(q, to float64, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w, got %g, capping to %g", InvalidRatioWarning, q, to),
|
Err: fmt.Errorf("%w, got %g, capping to %g", InvalidRatioWarning, q, to),
|
||||||
}
|
}
|
||||||
@ -187,8 +235,8 @@ func NewInvalidRatioWarning(q, to float64, pos posrange.PositionRange) error {
|
|||||||
|
|
||||||
// NewBadBucketLabelWarning is used when there is an error parsing the bucket label
|
// NewBadBucketLabelWarning is used when there is an error parsing the bucket label
|
||||||
// of a classic histogram.
|
// of a classic histogram.
|
||||||
func NewBadBucketLabelWarning(metricName, label string, pos posrange.PositionRange) error {
|
func NewBadBucketLabelWarning(metricName, label string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w of %q for metric name %q", BadBucketLabelWarning, label, metricName),
|
Err: fmt.Errorf("%w of %q for metric name %q", BadBucketLabelWarning, label, metricName),
|
||||||
}
|
}
|
||||||
@ -197,8 +245,8 @@ func NewBadBucketLabelWarning(metricName, label string, pos posrange.PositionRan
|
|||||||
// NewMixedFloatsHistogramsWarning is used when the queried series includes both
|
// NewMixedFloatsHistogramsWarning is used when the queried series includes both
|
||||||
// float samples and histogram samples for functions that do not support mixed
|
// float samples and histogram samples for functions that do not support mixed
|
||||||
// samples.
|
// samples.
|
||||||
func NewMixedFloatsHistogramsWarning(metricName string, pos posrange.PositionRange) error {
|
func NewMixedFloatsHistogramsWarning(metricName string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w metric name %q", MixedFloatsHistogramsWarning, metricName),
|
Err: fmt.Errorf("%w metric name %q", MixedFloatsHistogramsWarning, metricName),
|
||||||
}
|
}
|
||||||
@ -206,8 +254,8 @@ func NewMixedFloatsHistogramsWarning(metricName string, pos posrange.PositionRan
|
|||||||
|
|
||||||
// NewMixedFloatsHistogramsAggWarning is used when the queried series includes both
|
// NewMixedFloatsHistogramsAggWarning is used when the queried series includes both
|
||||||
// float samples and histogram samples in an aggregation.
|
// float samples and histogram samples in an aggregation.
|
||||||
func NewMixedFloatsHistogramsAggWarning(pos posrange.PositionRange) error {
|
func NewMixedFloatsHistogramsAggWarning(pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w aggregation", MixedFloatsHistogramsWarning),
|
Err: fmt.Errorf("%w aggregation", MixedFloatsHistogramsWarning),
|
||||||
}
|
}
|
||||||
@ -215,8 +263,8 @@ func NewMixedFloatsHistogramsAggWarning(pos posrange.PositionRange) error {
|
|||||||
|
|
||||||
// NewMixedClassicNativeHistogramsWarning is used when the queried series includes
|
// NewMixedClassicNativeHistogramsWarning is used when the queried series includes
|
||||||
// both classic and native histograms.
|
// both classic and native histograms.
|
||||||
func NewMixedClassicNativeHistogramsWarning(metricName string, pos posrange.PositionRange) error {
|
func NewMixedClassicNativeHistogramsWarning(metricName string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %q", MixedClassicNativeHistogramsWarning, metricName),
|
Err: fmt.Errorf("%w %q", MixedClassicNativeHistogramsWarning, metricName),
|
||||||
}
|
}
|
||||||
@ -224,8 +272,8 @@ func NewMixedClassicNativeHistogramsWarning(metricName string, pos posrange.Posi
|
|||||||
|
|
||||||
// NewNativeHistogramNotCounterWarning is used when histogramRate is called
|
// NewNativeHistogramNotCounterWarning is used when histogramRate is called
|
||||||
// with isCounter set to true on a gauge histogram.
|
// with isCounter set to true on a gauge histogram.
|
||||||
func NewNativeHistogramNotCounterWarning(metricName string, pos posrange.PositionRange) error {
|
func NewNativeHistogramNotCounterWarning(metricName string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %q", NativeHistogramNotCounterWarning, metricName),
|
Err: fmt.Errorf("%w %q", NativeHistogramNotCounterWarning, metricName),
|
||||||
}
|
}
|
||||||
@ -233,8 +281,8 @@ func NewNativeHistogramNotCounterWarning(metricName string, pos posrange.Positio
|
|||||||
|
|
||||||
// NewNativeHistogramNotGaugeWarning is used when histogramRate is called
|
// NewNativeHistogramNotGaugeWarning is used when histogramRate is called
|
||||||
// with isCounter set to false on a counter histogram.
|
// with isCounter set to false on a counter histogram.
|
||||||
func NewNativeHistogramNotGaugeWarning(metricName string, pos posrange.PositionRange) error {
|
func NewNativeHistogramNotGaugeWarning(metricName string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %q", NativeHistogramNotGaugeWarning, metricName),
|
Err: fmt.Errorf("%w %q", NativeHistogramNotGaugeWarning, metricName),
|
||||||
}
|
}
|
||||||
@ -242,8 +290,8 @@ func NewNativeHistogramNotGaugeWarning(metricName string, pos posrange.PositionR
|
|||||||
|
|
||||||
// NewMixedExponentialCustomHistogramsWarning is used when the queried series includes
|
// NewMixedExponentialCustomHistogramsWarning is used when the queried series includes
|
||||||
// histograms with both exponential and custom buckets schemas.
|
// histograms with both exponential and custom buckets schemas.
|
||||||
func NewMixedExponentialCustomHistogramsWarning(metricName string, pos posrange.PositionRange) error {
|
func NewMixedExponentialCustomHistogramsWarning(metricName string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %q", MixedExponentialCustomHistogramsWarning, metricName),
|
Err: fmt.Errorf("%w %q", MixedExponentialCustomHistogramsWarning, metricName),
|
||||||
}
|
}
|
||||||
@ -251,8 +299,8 @@ func NewMixedExponentialCustomHistogramsWarning(metricName string, pos posrange.
|
|||||||
|
|
||||||
// NewIncompatibleCustomBucketsHistogramsWarning is used when the queried series includes
|
// NewIncompatibleCustomBucketsHistogramsWarning is used when the queried series includes
|
||||||
// custom buckets histograms with incompatible custom bounds.
|
// custom buckets histograms with incompatible custom bounds.
|
||||||
func NewIncompatibleCustomBucketsHistogramsWarning(metricName string, pos posrange.PositionRange) error {
|
func NewIncompatibleCustomBucketsHistogramsWarning(metricName string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %q", IncompatibleCustomBucketsHistogramsWarning, metricName),
|
Err: fmt.Errorf("%w %q", IncompatibleCustomBucketsHistogramsWarning, metricName),
|
||||||
}
|
}
|
||||||
@ -260,8 +308,8 @@ func NewIncompatibleCustomBucketsHistogramsWarning(metricName string, pos posran
|
|||||||
|
|
||||||
// NewPossibleNonCounterInfo is used when a named counter metric with only float samples does not
|
// NewPossibleNonCounterInfo is used when a named counter metric with only float samples does not
|
||||||
// have the suffixes _total, _sum, _count, or _bucket.
|
// have the suffixes _total, _sum, _count, or _bucket.
|
||||||
func NewPossibleNonCounterInfo(metricName string, pos posrange.PositionRange) error {
|
func NewPossibleNonCounterInfo(metricName string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %q", PossibleNonCounterInfo, metricName),
|
Err: fmt.Errorf("%w %q", PossibleNonCounterInfo, metricName),
|
||||||
}
|
}
|
||||||
@ -269,8 +317,8 @@ func NewPossibleNonCounterInfo(metricName string, pos posrange.PositionRange) er
|
|||||||
|
|
||||||
// NewHistogramQuantileForcedMonotonicityInfo is used when the input (classic histograms) to
|
// NewHistogramQuantileForcedMonotonicityInfo is used when the input (classic histograms) to
|
||||||
// histogram_quantile needs to be forced to be monotonic.
|
// histogram_quantile needs to be forced to be monotonic.
|
||||||
func NewHistogramQuantileForcedMonotonicityInfo(metricName string, pos posrange.PositionRange) error {
|
func NewHistogramQuantileForcedMonotonicityInfo(metricName string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %q", HistogramQuantileForcedMonotonicityInfo, metricName),
|
Err: fmt.Errorf("%w %q", HistogramQuantileForcedMonotonicityInfo, metricName),
|
||||||
}
|
}
|
||||||
@ -278,8 +326,8 @@ func NewHistogramQuantileForcedMonotonicityInfo(metricName string, pos posrange.
|
|||||||
|
|
||||||
// NewIncompatibleTypesInBinOpInfo is used if binary operators act on a
|
// NewIncompatibleTypesInBinOpInfo is used if binary operators act on a
|
||||||
// combination of types that doesn't work and therefore returns no result.
|
// combination of types that doesn't work and therefore returns no result.
|
||||||
func NewIncompatibleTypesInBinOpInfo(lhsType, operator, rhsType string, pos posrange.PositionRange) error {
|
func NewIncompatibleTypesInBinOpInfo(lhsType, operator, rhsType string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %q: %s %s %s", IncompatibleTypesInBinOpInfo, operator, lhsType, operator, rhsType),
|
Err: fmt.Errorf("%w %q: %s %s %s", IncompatibleTypesInBinOpInfo, operator, lhsType, operator, rhsType),
|
||||||
}
|
}
|
||||||
@ -287,8 +335,8 @@ func NewIncompatibleTypesInBinOpInfo(lhsType, operator, rhsType string, pos posr
|
|||||||
|
|
||||||
// NewHistogramIgnoredInAggregationInfo is used when a histogram is ignored by
|
// NewHistogramIgnoredInAggregationInfo is used when a histogram is ignored by
|
||||||
// an aggregation operator that cannot handle histograms.
|
// an aggregation operator that cannot handle histograms.
|
||||||
func NewHistogramIgnoredInAggregationInfo(aggregation string, pos posrange.PositionRange) error {
|
func NewHistogramIgnoredInAggregationInfo(aggregation string, pos posrange.PositionRange) annoErr {
|
||||||
return annoErr{
|
return &genericAnnoErr{
|
||||||
PositionRange: pos,
|
PositionRange: pos,
|
||||||
Err: fmt.Errorf("%w %s aggregation", HistogramIgnoredInAggregationInfo, aggregation),
|
Err: fmt.Errorf("%w %s aggregation", HistogramIgnoredInAggregationInfo, aggregation),
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ package annotations
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -26,11 +27,16 @@ func TestAnnotations_AsStrings(t *testing.T) {
|
|||||||
var annos Annotations
|
var annos Annotations
|
||||||
pos := posrange.PositionRange{Start: 3, End: 8}
|
pos := posrange.PositionRange{Start: 3, End: 8}
|
||||||
|
|
||||||
annos.Add(errors.New("this is a non-annotation error"))
|
annos.AddRaw(errors.New("this is a non-annotation error"))
|
||||||
|
|
||||||
annos.Add(NewInvalidRatioWarning(1.1, 100, pos))
|
annos.Add(NewInvalidRatioWarning(1.1, 100, pos))
|
||||||
annos.Add(NewInvalidRatioWarning(1.2, 123, pos))
|
annos.Add(NewInvalidRatioWarning(1.2, 123, pos))
|
||||||
|
|
||||||
|
annos.Add(newTestCustomWarning(1.5, pos, 12, 14))
|
||||||
|
annos.Add(newTestCustomWarning(1.5, pos, 10, 20))
|
||||||
|
annos.Add(newTestCustomWarning(1.5, pos, 5, 15))
|
||||||
|
annos.Add(newTestCustomWarning(1.5, pos, 12, 14))
|
||||||
|
|
||||||
annos.Add(NewHistogramIgnoredInAggregationInfo("sum", pos))
|
annos.Add(NewHistogramIgnoredInAggregationInfo("sum", pos))
|
||||||
|
|
||||||
warnings, infos := annos.AsStrings("lorem ipsum dolor sit amet", 0, 0)
|
warnings, infos := annos.AsStrings("lorem ipsum dolor sit amet", 0, 0)
|
||||||
@ -38,8 +44,65 @@ func TestAnnotations_AsStrings(t *testing.T) {
|
|||||||
"this is a non-annotation error",
|
"this is a non-annotation error",
|
||||||
"PromQL warning: ratio value should be between -1 and 1, got 1.1, capping to 100 (1:4)",
|
"PromQL warning: ratio value should be between -1 and 1, got 1.1, capping to 100 (1:4)",
|
||||||
"PromQL warning: ratio value should be between -1 and 1, got 1.2, capping to 123 (1:4)",
|
"PromQL warning: ratio value should be between -1 and 1, got 1.2, capping to 123 (1:4)",
|
||||||
|
"PromQL warning: custom value set to 1.5, 4 instances with smallest 5 and biggest 20 (1:4)",
|
||||||
})
|
})
|
||||||
require.ElementsMatch(t, infos, []string{
|
require.ElementsMatch(t, infos, []string{
|
||||||
"PromQL info: ignored histogram in sum aggregation (1:4)",
|
"PromQL info: ignored histogram in sum aggregation (1:4)",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testCustomError struct {
|
||||||
|
PositionRange posrange.PositionRange
|
||||||
|
Err error
|
||||||
|
Query string
|
||||||
|
Min []float64
|
||||||
|
Max []float64
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testCustomError) merge(other annoErr) annoErr {
|
||||||
|
o, ok := other.(*testCustomError)
|
||||||
|
if !ok {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
if e.Err.Error() != o.Err.Error() || len(e.Min) != len(o.Min) || len(e.Max) != len(o.Max) {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
for i, aMin := range e.Min {
|
||||||
|
if aMin < o.Min[i] {
|
||||||
|
o.Min[i] = aMin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, aMax := range e.Max {
|
||||||
|
if aMax > o.Max[i] {
|
||||||
|
o.Max[i] = aMax
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o.Count += e.Count + 1
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testCustomError) setQuery(query string) {
|
||||||
|
e.Query = query
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testCustomError) Error() string {
|
||||||
|
if e.Query == "" {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s, %d instances with smallest %g and biggest %g (%s)", e.Err, e.Count+1, e.Min[0], e.Max[0], e.PositionRange.StartPosInput(e.Query, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testCustomError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestCustomWarning(q float64, pos posrange.PositionRange, smallest, largest float64) annoErr {
|
||||||
|
testCustomWarning := fmt.Errorf("%w: custom value set to", PromQLWarning)
|
||||||
|
return &testCustomError{
|
||||||
|
PositionRange: pos,
|
||||||
|
Err: fmt.Errorf("%w %g", testCustomWarning, q),
|
||||||
|
Min: []float64{smallest},
|
||||||
|
Max: []float64{largest},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -84,7 +84,11 @@ const (
|
|||||||
errorNotAcceptable errorType = "not_acceptable"
|
errorNotAcceptable errorType = "not_acceptable"
|
||||||
)
|
)
|
||||||
|
|
||||||
var LocalhostRepresentations = []string{"127.0.0.1", "localhost", "::1"}
|
var (
|
||||||
|
LocalhostRepresentations = []string{"127.0.0.1", "localhost", "::1"}
|
||||||
|
|
||||||
|
errResultsTruncatedLimit = errors.New("results truncated due to limit")
|
||||||
|
)
|
||||||
|
|
||||||
type apiError struct {
|
type apiError struct {
|
||||||
typ errorType
|
typ errorType
|
||||||
@ -735,7 +739,7 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
|
|||||||
|
|
||||||
if limit > 0 && len(names) > limit {
|
if limit > 0 && len(names) > limit {
|
||||||
names = names[:limit]
|
names = names[:limit]
|
||||||
warnings = warnings.Add(errors.New("results truncated due to limit"))
|
warnings = warnings.AddRaw(errResultsTruncatedLimit)
|
||||||
}
|
}
|
||||||
return apiFuncResult{names, nil, warnings, nil}
|
return apiFuncResult{names, nil, warnings, nil}
|
||||||
}
|
}
|
||||||
@ -833,7 +837,7 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {
|
|||||||
|
|
||||||
if limit > 0 && len(vals) > limit {
|
if limit > 0 && len(vals) > limit {
|
||||||
vals = vals[:limit]
|
vals = vals[:limit]
|
||||||
warnings = warnings.Add(errors.New("results truncated due to limit"))
|
warnings = warnings.AddRaw(errResultsTruncatedLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiFuncResult{vals, nil, warnings, closer}
|
return apiFuncResult{vals, nil, warnings, closer}
|
||||||
@ -940,7 +944,7 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
|
|||||||
|
|
||||||
if limit > 0 && len(metrics) > limit {
|
if limit > 0 && len(metrics) > limit {
|
||||||
metrics = metrics[:limit]
|
metrics = metrics[:limit]
|
||||||
warnings.Add(errors.New("results truncated due to limit"))
|
warnings.AddRaw(errResultsTruncatedLimit)
|
||||||
return apiFuncResult{metrics, nil, warnings, closer}
|
return apiFuncResult{metrics, nil, warnings, closer}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user