2013-02-07 02:49:04 -08:00
|
|
|
// 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.
|
|
|
|
|
2013-01-07 14:24:26 -08:00
|
|
|
package ast
|
|
|
|
|
|
|
|
import (
|
2013-01-25 03:21:44 -08:00
|
|
|
"flag"
|
2013-01-27 09:49:45 -08:00
|
|
|
"github.com/prometheus/prometheus/model"
|
|
|
|
"github.com/prometheus/prometheus/storage/metric"
|
2013-01-07 14:24:26 -08:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2013-01-25 03:21:44 -08:00
|
|
|
var defaultStalenessDelta = flag.Int("defaultStalenessDelta", 300, "Default staleness delta allowance in seconds during expression evaluations.")
|
2013-01-07 14:24:26 -08:00
|
|
|
|
2013-03-21 10:06:15 -07:00
|
|
|
// AST-global storage to use for operations that are not supported by views
|
|
|
|
// (i.e. metric->fingerprint lookups).
|
|
|
|
var queryStorage metric.Storage = nil
|
|
|
|
|
|
|
|
type viewAdapter struct {
|
|
|
|
view metric.View
|
|
|
|
// TODO: use this.
|
2013-01-25 03:21:44 -08:00
|
|
|
stalenessPolicy *metric.StalenessPolicy
|
2013-01-07 14:24:26 -08:00
|
|
|
}
|
|
|
|
|
2013-03-21 10:06:15 -07:00
|
|
|
func (v *viewAdapter) chooseClosestSample(samples []model.SamplePair, timestamp *time.Time) (sample *model.SamplePair) {
|
|
|
|
var minDelta time.Duration
|
|
|
|
for _, candidate := range samples {
|
|
|
|
// Ignore samples outside of staleness policy window.
|
|
|
|
delta := candidate.Timestamp.Sub(*timestamp)
|
|
|
|
if delta < 0 {
|
|
|
|
delta = -delta
|
|
|
|
}
|
|
|
|
if delta > v.stalenessPolicy.DeltaAllowance {
|
|
|
|
continue
|
|
|
|
}
|
2013-01-07 14:24:26 -08:00
|
|
|
|
2013-03-21 10:06:15 -07:00
|
|
|
// Skip sample if we've seen a closer one before this.
|
|
|
|
if sample != nil {
|
|
|
|
if delta > minDelta {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sample = &candidate
|
|
|
|
minDelta = delta
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-03-27 06:06:30 -07:00
|
|
|
func (v *viewAdapter) GetValueAtTime(fingerprints model.Fingerprints, timestamp *time.Time) (samples []*model.Sample, err error) {
|
2013-01-07 14:24:26 -08:00
|
|
|
for _, fingerprint := range fingerprints {
|
2013-03-21 10:06:15 -07:00
|
|
|
sampleCandidates := v.view.GetValueAtTime(fingerprint, *timestamp)
|
|
|
|
samplePair := v.chooseClosestSample(sampleCandidates, timestamp)
|
|
|
|
m, err := queryStorage.GetMetricForFingerprint(fingerprint)
|
2013-01-07 14:24:26 -08:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2013-03-21 10:06:15 -07:00
|
|
|
if samplePair != nil {
|
|
|
|
samples = append(samples, &model.Sample{
|
|
|
|
Metric: *m,
|
|
|
|
Value: samplePair.Value,
|
|
|
|
Timestamp: *timestamp,
|
|
|
|
})
|
|
|
|
}
|
2013-01-07 14:24:26 -08:00
|
|
|
}
|
2013-03-18 09:12:51 -07:00
|
|
|
return
|
2013-01-07 14:24:26 -08:00
|
|
|
}
|
|
|
|
|
2013-03-27 06:06:30 -07:00
|
|
|
func (v *viewAdapter) GetBoundaryValues(fingerprints model.Fingerprints, interval *model.Interval) (sampleSets []*model.SampleSet, err error) {
|
2013-03-18 09:12:51 -07:00
|
|
|
for _, fingerprint := range fingerprints {
|
2013-01-12 12:22:59 -08:00
|
|
|
// TODO: change to GetBoundaryValues() once it has the right return type.
|
2013-03-21 10:06:15 -07:00
|
|
|
samplePairs := v.view.GetRangeValues(fingerprint, *interval)
|
|
|
|
if samplePairs == nil {
|
|
|
|
continue
|
2013-01-10 16:19:27 -08:00
|
|
|
}
|
2013-03-21 10:06:15 -07:00
|
|
|
|
|
|
|
// TODO: memoize/cache this.
|
|
|
|
m, err := queryStorage.GetMetricForFingerprint(fingerprint)
|
|
|
|
if err != nil {
|
2013-01-10 16:19:27 -08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2013-03-21 10:06:15 -07:00
|
|
|
sampleSet := &model.SampleSet{
|
|
|
|
Metric: *m,
|
|
|
|
Values: samplePairs,
|
|
|
|
}
|
2013-01-10 16:19:27 -08:00
|
|
|
sampleSets = append(sampleSets, sampleSet)
|
|
|
|
}
|
|
|
|
return sampleSets, nil
|
2013-01-07 14:24:26 -08:00
|
|
|
}
|
|
|
|
|
2013-03-27 06:06:30 -07:00
|
|
|
func (v *viewAdapter) GetRangeValues(fingerprints model.Fingerprints, interval *model.Interval) (sampleSets []*model.SampleSet, err error) {
|
2013-03-18 09:12:51 -07:00
|
|
|
for _, fingerprint := range fingerprints {
|
2013-03-21 10:06:15 -07:00
|
|
|
samplePairs := v.view.GetRangeValues(fingerprint, *interval)
|
|
|
|
if samplePairs == nil {
|
|
|
|
continue
|
2013-01-10 16:19:27 -08:00
|
|
|
}
|
2013-03-21 10:06:15 -07:00
|
|
|
|
|
|
|
// TODO: memoize/cache this.
|
|
|
|
m, err := queryStorage.GetMetricForFingerprint(fingerprint)
|
|
|
|
if err != nil {
|
2013-01-10 16:19:27 -08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2013-03-21 10:06:15 -07:00
|
|
|
sampleSet := &model.SampleSet{
|
|
|
|
Metric: *m,
|
|
|
|
Values: samplePairs,
|
|
|
|
}
|
2013-01-10 16:19:27 -08:00
|
|
|
sampleSets = append(sampleSets, sampleSet)
|
|
|
|
}
|
|
|
|
return sampleSets, nil
|
2013-01-07 14:24:26 -08:00
|
|
|
}
|
|
|
|
|
2013-03-21 10:06:15 -07:00
|
|
|
func SetStorage(storage metric.Storage) {
|
|
|
|
queryStorage = storage
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewViewAdapter(view metric.View) *viewAdapter {
|
|
|
|
stalenessPolicy := metric.StalenessPolicy{
|
|
|
|
DeltaAllowance: time.Duration(*defaultStalenessDelta) * time.Second,
|
2013-01-25 03:21:44 -08:00
|
|
|
}
|
2013-03-21 10:06:15 -07:00
|
|
|
|
|
|
|
return &viewAdapter{
|
|
|
|
view: view,
|
|
|
|
stalenessPolicy: &stalenessPolicy,
|
2013-01-07 14:24:26 -08:00
|
|
|
}
|
|
|
|
}
|