mirror of https://github.com/prometheus/prometheus
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
6.0 KiB
262 lines
6.0 KiB
// 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 model |
|
|
|
import ( |
|
"bytes" |
|
"code.google.com/p/goprotobuf/proto" |
|
"fmt" |
|
dto "github.com/prometheus/prometheus/model/generated" |
|
"sort" |
|
"strings" |
|
"time" |
|
) |
|
|
|
const ( |
|
// XXX: Re-evaluate down the road. |
|
reservedDelimiter = `"` |
|
) |
|
|
|
// A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet |
|
// may be fully-qualified down to the point where it may resolve to a single |
|
// Metric in the data store or not. All operations that occur within the realm |
|
// of a LabelSet can emit a vector of Metric entities to which the LabelSet may |
|
// match. |
|
type LabelSet map[LabelName]LabelValue |
|
|
|
// Helper function to non-destructively merge two label sets. |
|
func (l LabelSet) Merge(other LabelSet) LabelSet { |
|
result := make(LabelSet, len(l)) |
|
|
|
for k, v := range l { |
|
result[k] = v |
|
} |
|
|
|
for k, v := range other { |
|
result[k] = v |
|
} |
|
|
|
return result |
|
} |
|
|
|
func (l LabelSet) String() string { |
|
labelStrings := make([]string, 0, len(l)) |
|
for label, value := range l { |
|
labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value)) |
|
} |
|
|
|
switch len(labelStrings) { |
|
case 0: |
|
return "" |
|
default: |
|
sort.Strings(labelStrings) |
|
return fmt.Sprintf("{%s}", strings.Join(labelStrings, ", ")) |
|
} |
|
} |
|
|
|
func (m Metric) String() string { |
|
metricName, ok := m[MetricNameLabel] |
|
if !ok { |
|
panic("Tried to print metric without name") |
|
} |
|
labelStrings := make([]string, 0, len(m)-1) |
|
for label, value := range m { |
|
if label != MetricNameLabel { |
|
labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value)) |
|
} |
|
} |
|
|
|
switch len(labelStrings) { |
|
case 0: |
|
return string(metricName) |
|
default: |
|
sort.Strings(labelStrings) |
|
return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ", ")) |
|
} |
|
} |
|
|
|
func (l LabelSet) ToMetric() Metric { |
|
metric := Metric{} |
|
for label, value := range l { |
|
metric[label] = value |
|
} |
|
return metric |
|
} |
|
|
|
func (m Metric) ToLabelSet() LabelSet { |
|
labels := LabelSet{} |
|
for label, value := range m { |
|
labels[label] = value |
|
} |
|
return labels |
|
} |
|
|
|
// A Metric is similar to a LabelSet, but the key difference is that a Metric is |
|
// a singleton and refers to one and only one stream of samples. |
|
type Metric map[LabelName]LabelValue |
|
|
|
// A SampleValue is a representation of a value for a given sample at a given |
|
// time. |
|
type SampleValue float64 |
|
|
|
func (s SampleValue) Equal(o SampleValue) bool { |
|
return s == o |
|
} |
|
|
|
func (s SampleValue) ToDTO() *float64 { |
|
return proto.Float64(float64(s)) |
|
} |
|
|
|
func (v SampleValue) MarshalJSON() ([]byte, error) { |
|
return []byte(fmt.Sprintf(`"%f"`, v)), nil |
|
} |
|
|
|
func (v SampleValue) String() string { |
|
return fmt.Sprint(float64(v)) |
|
} |
|
|
|
func (s SamplePair) MarshalJSON() ([]byte, error) { |
|
return []byte(fmt.Sprintf("{\"Value\": \"%f\", \"Timestamp\": %d}", s.Value, s.Timestamp.Unix())), nil |
|
} |
|
|
|
type SamplePair struct { |
|
Value SampleValue |
|
Timestamp time.Time |
|
} |
|
|
|
func (s SamplePair) Equal(o SamplePair) bool { |
|
return s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp) |
|
} |
|
|
|
func (s SamplePair) ToDTO() (out *dto.SampleValueSeries_Value) { |
|
out = &dto.SampleValueSeries_Value{ |
|
Timestamp: proto.Int64(s.Timestamp.Unix()), |
|
Value: s.Value.ToDTO(), |
|
} |
|
|
|
return |
|
} |
|
|
|
func (s SamplePair) String() string { |
|
return fmt.Sprintf("SamplePair at %s of %s", s.Timestamp, s.Value) |
|
} |
|
|
|
type Values []SamplePair |
|
|
|
func (v Values) Len() int { |
|
return len(v) |
|
} |
|
|
|
func (v Values) Less(i, j int) bool { |
|
return v[i].Timestamp.Before(v[j].Timestamp) |
|
} |
|
|
|
func (v Values) Swap(i, j int) { |
|
v[i], v[j] = v[j], v[i] |
|
} |
|
|
|
// FirstTimeAfter indicates whether the first sample of a set is after a given |
|
// timestamp. |
|
func (v Values) FirstTimeAfter(t time.Time) bool { |
|
return v[0].Timestamp.After(t) |
|
} |
|
|
|
// LastTimeBefore indicates whether the last sample of a set is before a given |
|
// timestamp. |
|
func (v Values) LastTimeBefore(t time.Time) bool { |
|
return v[len(v)-1].Timestamp.Before(t) |
|
} |
|
|
|
// InsideInterval indicates whether a given range of sorted values could contain |
|
// a value for a given time. |
|
func (v Values) InsideInterval(t time.Time) bool { |
|
switch { |
|
case v.Len() == 0: |
|
return false |
|
case t.Before(v[0].Timestamp): |
|
return false |
|
case !v[v.Len()-1].Timestamp.Before(t): |
|
return false |
|
default: |
|
return true |
|
} |
|
} |
|
|
|
// TruncateBefore returns a subslice of the original such that extraneous |
|
// samples in the collection that occur before the provided time are |
|
// dropped. The original slice is not mutated |
|
func (v Values) TruncateBefore(t time.Time) Values { |
|
index := sort.Search(len(v), func(i int) bool { |
|
timestamp := v[i].Timestamp |
|
|
|
return !timestamp.Before(t) |
|
}) |
|
|
|
return v[index:] |
|
} |
|
|
|
func (v Values) ToDTO() (out *dto.SampleValueSeries) { |
|
out = &dto.SampleValueSeries{} |
|
|
|
for _, value := range v { |
|
out.Value = append(out.Value, value.ToDTO()) |
|
} |
|
|
|
return |
|
} |
|
|
|
func (v Values) ToSampleKey(f *Fingerprint) SampleKey { |
|
return SampleKey{ |
|
Fingerprint: f, |
|
FirstTimestamp: v[0].Timestamp, |
|
LastTimestamp: v[len(v)-1].Timestamp, |
|
SampleCount: uint32(len(v)), |
|
} |
|
} |
|
|
|
func (v Values) String() string { |
|
buffer := bytes.Buffer{} |
|
|
|
fmt.Fprintf(&buffer, "[") |
|
for i, value := range v { |
|
fmt.Fprintf(&buffer, "%d. %s", i, value) |
|
if i != len(v)-1 { |
|
fmt.Fprintf(&buffer, "\n") |
|
} |
|
} |
|
fmt.Fprintf(&buffer, "]") |
|
|
|
return buffer.String() |
|
} |
|
|
|
func NewValuesFromDTO(dto *dto.SampleValueSeries) (v Values) { |
|
for _, value := range dto.Value { |
|
v = append(v, SamplePair{ |
|
Timestamp: time.Unix(*value.Timestamp, 0).UTC(), |
|
Value: SampleValue(*value.Value), |
|
}) |
|
} |
|
|
|
return v |
|
} |
|
|
|
type SampleSet struct { |
|
Metric Metric |
|
Values Values |
|
} |
|
|
|
type Interval struct { |
|
OldestInclusive time.Time |
|
NewestInclusive time.Time |
|
}
|
|
|