diff --git a/rules/ast/functions.go b/rules/ast/functions.go index a392bb736..7fba2b116 100644 --- a/rules/ast/functions.go +++ b/rules/ast/functions.go @@ -85,6 +85,12 @@ func deltaImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} matrixValue = matrixNode.EvalBoundaries(timestamp, view) } for _, samples := range matrixValue { + // No sense in trying to compute a delta without at least two points. Drop + // this vector element. + if len(samples.Values) < 2 { + continue + } + counterCorrection := model.SampleValue(0) lastValue := model.SampleValue(0) for _, sample := range samples.Values { diff --git a/rules/ast/functions_test.go b/rules/ast/functions_test.go new file mode 100644 index 000000000..486d54250 --- /dev/null +++ b/rules/ast/functions_test.go @@ -0,0 +1,56 @@ +// Copyright 2013 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ast + +import ( + "github.com/prometheus/prometheus/model" + "testing" + "time" +) + +type emptyRangeNode struct{} + +func (node emptyRangeNode) Type() ExprType { return MATRIX } +func (node emptyRangeNode) NodeTreeToDotGraph() string { return "" } +func (node emptyRangeNode) Children() []Node { return []Node{} } + +func (node emptyRangeNode) Eval(timestamp time.Time, view *viewAdapter) Matrix { + return Matrix{ + model.SampleSet{ + Metric: model.Metric{model.MetricNameLabel: "empty_metric"}, + Values: model.Values{}, + }, + } +} + +func (node emptyRangeNode) EvalBoundaries(timestamp time.Time, view *viewAdapter) Matrix { + return Matrix{ + model.SampleSet{ + Metric: model.Metric{model.MetricNameLabel: "empty_metric"}, + Values: model.Values{}, + }, + } +} + +func TestDeltaWithEmptyElementDoesNotCrash(t *testing.T) { + now := time.Now() + vector := deltaImpl(now, nil, []Node{emptyRangeNode{}, &ScalarLiteral{value: 0}}).(Vector) + if len(vector) != 0 { + t.Fatalf("Expected empty result vector, got: %v", vector) + } + vector = deltaImpl(now, nil, []Node{emptyRangeNode{}, &ScalarLiteral{value: 1}}).(Vector) + if len(vector) != 0 { + t.Fatalf("Expected empty result vector, got: %v", vector) + } +}