Merge pull request #17248 from prometheus/beorn7/histogram
buf.build / lint and publish (push) Waiting to run Details
CI / Go tests (push) Waiting to run Details
CI / More Go tests (push) Waiting to run Details
CI / Go tests with previous Go version (push) Waiting to run Details
CI / UI tests (push) Waiting to run Details
CI / Go tests on Windows (push) Waiting to run Details
CI / Mixins tests (push) Waiting to run Details
CI / Build Prometheus for common architectures (0) (push) Waiting to run Details
CI / Build Prometheus for common architectures (1) (push) Waiting to run Details
CI / Build Prometheus for common architectures (2) (push) Waiting to run Details
CI / Build Prometheus for all architectures (0) (push) Waiting to run Details
CI / Build Prometheus for all architectures (1) (push) Waiting to run Details
CI / Build Prometheus for all architectures (10) (push) Waiting to run Details
CI / Build Prometheus for all architectures (11) (push) Waiting to run Details
CI / Build Prometheus for all architectures (2) (push) Waiting to run Details
CI / Build Prometheus for all architectures (3) (push) Waiting to run Details
CI / Build Prometheus for all architectures (4) (push) Waiting to run Details
CI / Build Prometheus for all architectures (5) (push) Waiting to run Details
CI / Build Prometheus for all architectures (6) (push) Waiting to run Details
CI / Build Prometheus for all architectures (7) (push) Waiting to run Details
CI / Build Prometheus for all architectures (8) (push) Waiting to run Details
CI / Build Prometheus for all architectures (9) (push) Waiting to run Details
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions Details
CI / Check generated parser (push) Waiting to run Details
CI / golangci-lint (push) Waiting to run Details
CI / fuzzing (push) Waiting to run Details
CI / codeql (push) Waiting to run Details
CI / Publish main branch artifacts (push) Blocked by required conditions Details
CI / Publish release artefacts (push) Blocked by required conditions Details
CI / Publish UI on npm Registry (push) Blocked by required conditions Details
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run Details

model/histogram: Validate non-negative count and zero bucket
This commit is contained in:
Björn Rabenstein 2025-10-01 18:05:14 +02:00 committed by GitHub
commit 12c0961fd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 102 additions and 0 deletions

View File

@ -826,12 +826,18 @@ func (h *FloatHistogram) Validate() error {
if err != nil {
return fmt.Errorf("negative side: %w", err)
}
if h.ZeroCount < 0 {
return fmt.Errorf("zero bucket has observation count of %v: %w", h.ZeroCount, ErrHistogramNegativeBucketCount)
}
if h.CustomValues != nil {
return ErrHistogramExpSchemaCustomBounds
}
default:
return InvalidSchemaError(h.Schema)
}
if h.Count < 0 {
return fmt.Errorf("observation count is %v: %w", h.Count, ErrHistogramNegativeCount)
}
err := checkHistogramBuckets(h.PositiveBuckets, &pCount, false)
if err != nil {
return fmt.Errorf("positive side: %w", err)

View File

@ -3527,6 +3527,100 @@ func TestFloatHistogramString(t *testing.T) {
}
}
func TestFloatHistogramValidateNegativeHistogram(t *testing.T) {
cases := []struct {
name string
fh *FloatHistogram
}{
{
"positive bucket with negative population",
&FloatHistogram{
Schema: 1,
ZeroThreshold: 0.01,
ZeroCount: 5.5,
Count: 3493.3,
Sum: 2349209.324,
PositiveSpans: []Span{
{-2, 1},
{2, 3},
},
PositiveBuckets: []float64{1, 3.3, -4.2, 0.1},
NegativeSpans: []Span{
{3, 2},
{3, 2},
},
NegativeBuckets: []float64{3.1, 3, 1.234e5, 1000},
},
},
{
"negative bucket with negative population",
&FloatHistogram{
Schema: 1,
ZeroThreshold: 0.01,
ZeroCount: 5.5,
Count: 3493.3,
Sum: 2349209.324,
PositiveSpans: []Span{
{-2, 1},
{2, 3},
},
PositiveBuckets: []float64{1, 3.3, 4.2, 0.1},
NegativeSpans: []Span{
{3, 2},
{3, 2},
},
NegativeBuckets: []float64{3.1, -3, 1.234e5, 1000},
},
},
{
"negative count",
&FloatHistogram{
Schema: 1,
ZeroThreshold: 0.01,
ZeroCount: 5.5,
Count: -3493.3,
Sum: 2349209.324,
PositiveSpans: []Span{
{-2, 1},
{2, 3},
},
PositiveBuckets: []float64{1, 3.3, 4.2, 0.1},
NegativeSpans: []Span{
{3, 2},
{3, 2},
},
NegativeBuckets: []float64{3.1, 3, 1.234e5, 1000},
},
},
{
"zero bucket with negative population",
&FloatHistogram{
Schema: 1,
ZeroThreshold: 0.01,
ZeroCount: -5.5,
Count: 3493.3,
Sum: 2349209.324,
PositiveSpans: []Span{
{-2, 1},
{2, 3},
},
PositiveBuckets: []float64{1, 3.3, 4.2, 0.1},
NegativeSpans: []Span{
{3, 2},
{3, 2},
},
NegativeBuckets: []float64{3.1, 3, 1.234e5, 1000},
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
require.Error(t, c.fh.Validate())
})
}
}
func BenchmarkFloatHistogramAllBucketIterator(b *testing.B) {
rng := rand.New(rand.NewSource(0))

View File

@ -31,6 +31,7 @@ const (
var (
ErrHistogramCountNotBigEnough = errors.New("histogram's observation count should be at least the number of observations found in the buckets")
ErrHistogramCountMismatch = errors.New("histogram's observation count should equal the number of observations found in the buckets (in absence of NaN)")
ErrHistogramNegativeCount = errors.New("histogram's observation count is negative")
ErrHistogramNegativeBucketCount = errors.New("histogram has a bucket whose observation count is negative")
ErrHistogramSpanNegativeOffset = errors.New("histogram has a span whose offset is negative")
ErrHistogramSpansBucketsMismatch = errors.New("histogram spans specify different number of buckets than provided")

View File

@ -122,6 +122,7 @@ func isHistogramValidationError(err error) bool {
// TODO: Consider adding single histogram error type instead of individual sentinel errors.
return errors.Is(err, histogram.ErrHistogramCountMismatch) ||
errors.Is(err, histogram.ErrHistogramCountNotBigEnough) ||
errors.Is(err, histogram.ErrHistogramNegativeCount) ||
errors.Is(err, histogram.ErrHistogramNegativeBucketCount) ||
errors.Is(err, histogram.ErrHistogramSpanNegativeOffset) ||
errors.Is(err, histogram.ErrHistogramSpansBucketsMismatch) ||