// 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 } // 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 }