mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Vendor common/model package
This commit is contained in:
parent
a7c248e3b1
commit
7a6d12a44c
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
|
@ -58,6 +58,10 @@
|
||||||
"ImportPath": "github.com/prometheus/client_golang/text",
|
"ImportPath": "github.com/prometheus/client_golang/text",
|
||||||
"Rev": "3a499bf7fc46bc58337ce612d0cbb29c550b8118"
|
"Rev": "3a499bf7fc46bc58337ce612d0cbb29c550b8118"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/prometheus/common/model",
|
||||||
|
"Rev": "2502df85be1b9482ed669faa6b7cfe7f850eb08e"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/prometheus/client_model/go",
|
"ImportPath": "github.com/prometheus/client_model/go",
|
||||||
"Comment": "model-0.0.2-12-gfa8ad6f",
|
"Comment": "model-0.0.2-12-gfa8ad6f",
|
||||||
|
|
105
Godeps/_workspace/src/github.com/prometheus/common/model/fingerprinting.go
generated
vendored
Normal file
105
Godeps/_workspace/src/github.com/prometheus/common/model/fingerprinting.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fingerprint provides a hash-capable representation of a Metric.
|
||||||
|
// For our purposes, FNV-1A 64-bit is used.
|
||||||
|
type Fingerprint uint64
|
||||||
|
|
||||||
|
// FingerprintFromString transforms a string representation into a Fingerprint.
|
||||||
|
func FingerprintFromString(s string) (Fingerprint, error) {
|
||||||
|
num, err := strconv.ParseUint(s, 16, 64)
|
||||||
|
return Fingerprint(num), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseFingerprint parses the input string into a fingerprint.
|
||||||
|
func ParseFingerprint(s string) (Fingerprint, error) {
|
||||||
|
num, err := strconv.ParseUint(s, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return Fingerprint(num), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Fingerprint) String() string {
|
||||||
|
return fmt.Sprintf("%016x", uint64(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fingerprints represents a collection of Fingerprint subject to a given
|
||||||
|
// natural sorting scheme. It implements sort.Interface.
|
||||||
|
type Fingerprints []Fingerprint
|
||||||
|
|
||||||
|
// Len implements sort.Interface.
|
||||||
|
func (f Fingerprints) Len() int {
|
||||||
|
return len(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less implements sort.Interface.
|
||||||
|
func (f Fingerprints) Less(i, j int) bool {
|
||||||
|
return f[i] < f[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap implements sort.Interface.
|
||||||
|
func (f Fingerprints) Swap(i, j int) {
|
||||||
|
f[i], f[j] = f[j], f[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// FingerprintSet is a set of Fingerprints.
|
||||||
|
type FingerprintSet map[Fingerprint]struct{}
|
||||||
|
|
||||||
|
// Equal returns true if both sets contain the same elements (and not more).
|
||||||
|
func (s FingerprintSet) Equal(o FingerprintSet) bool {
|
||||||
|
if len(s) != len(o) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range s {
|
||||||
|
if _, ok := o[k]; !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intersection returns the elements contained in both sets.
|
||||||
|
func (s FingerprintSet) Intersection(o FingerprintSet) FingerprintSet {
|
||||||
|
myLength, otherLength := len(s), len(o)
|
||||||
|
if myLength == 0 || otherLength == 0 {
|
||||||
|
return FingerprintSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
subSet := s
|
||||||
|
superSet := o
|
||||||
|
|
||||||
|
if otherLength < myLength {
|
||||||
|
subSet = o
|
||||||
|
superSet = s
|
||||||
|
}
|
||||||
|
|
||||||
|
out := FingerprintSet{}
|
||||||
|
|
||||||
|
for k := range subSet {
|
||||||
|
if _, ok := superSet[k]; ok {
|
||||||
|
out[k] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
185
Godeps/_workspace/src/github.com/prometheus/common/model/labels.go
generated
vendored
Normal file
185
Godeps/_workspace/src/github.com/prometheus/common/model/labels.go
generated
vendored
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ExportedLabelPrefix is the prefix to prepend to the label names present in
|
||||||
|
// exported metrics if a label of the same name is added by the server.
|
||||||
|
ExportedLabelPrefix LabelName = "exported_"
|
||||||
|
|
||||||
|
// MetricNameLabel is the label name indicating the metric name of a
|
||||||
|
// timeseries.
|
||||||
|
MetricNameLabel LabelName = "__name__"
|
||||||
|
|
||||||
|
// SchemeLabel is the name of the label that holds the scheme on which to
|
||||||
|
// scrape a target.
|
||||||
|
SchemeLabel LabelName = "__scheme__"
|
||||||
|
|
||||||
|
// AddressLabel is the name of the label that holds the address of
|
||||||
|
// a scrape target.
|
||||||
|
AddressLabel LabelName = "__address__"
|
||||||
|
|
||||||
|
// MetricsPathLabel is the name of the label that holds the path on which to
|
||||||
|
// scrape a target.
|
||||||
|
MetricsPathLabel LabelName = "__metrics_path__"
|
||||||
|
|
||||||
|
// ReservedLabelPrefix is a prefix which is not legal in user-supplied
|
||||||
|
// label names.
|
||||||
|
ReservedLabelPrefix = "__"
|
||||||
|
|
||||||
|
// MetaLabelPrefix is a prefix for labels that provide meta information.
|
||||||
|
// Labels with this prefix are used for intermediate label processing and
|
||||||
|
// will not be attached to time series.
|
||||||
|
MetaLabelPrefix = "__meta_"
|
||||||
|
|
||||||
|
// TmpLabelPrefix is a prefix for temporary labels as part of relabelling.
|
||||||
|
// Labels with this prefix are used for intermediate label processing and
|
||||||
|
// will not be attached to time series. This is reserved for use in
|
||||||
|
// Prometheus configuration files by users.
|
||||||
|
TmpLabelPrefix = "__tmp_"
|
||||||
|
|
||||||
|
// ParamLabelPrefix is a prefix for labels that provide URL parameters
|
||||||
|
// used to scrape a target.
|
||||||
|
ParamLabelPrefix = "__param_"
|
||||||
|
|
||||||
|
// JobLabel is the label name indicating the job from which a timeseries
|
||||||
|
// was scraped.
|
||||||
|
JobLabel LabelName = "job"
|
||||||
|
|
||||||
|
// InstanceLabel is the label name used for the instance label.
|
||||||
|
InstanceLabel LabelName = "instance"
|
||||||
|
|
||||||
|
// BucketLabel is used for the label that defines the upper bound of a
|
||||||
|
// bucket of a histogram ("le" -> "less or equal").
|
||||||
|
BucketLabel = "le"
|
||||||
|
|
||||||
|
// QuantileLabel is used for the label that defines the quantile in a
|
||||||
|
// summary.
|
||||||
|
QuantileLabel = "quantile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LabelNameRE is a regular expression matching valid label names.
|
||||||
|
var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||||
|
|
||||||
|
// A LabelName is a key for a LabelSet or Metric. It has a value associated
|
||||||
|
// therewith.
|
||||||
|
type LabelName string
|
||||||
|
|
||||||
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
var s string
|
||||||
|
if err := unmarshal(&s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !LabelNameRE.MatchString(s) {
|
||||||
|
return fmt.Errorf("%q is not a valid label name", s)
|
||||||
|
}
|
||||||
|
*ln = LabelName(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (ln *LabelName) UnmarshalJSON(b []byte) error {
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(b, &s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !LabelNameRE.MatchString(s) {
|
||||||
|
return fmt.Errorf("%q is not a valid label name", s)
|
||||||
|
}
|
||||||
|
*ln = LabelName(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LabelNames is a sortable LabelName slice. In implements sort.Interface.
|
||||||
|
type LabelNames []LabelName
|
||||||
|
|
||||||
|
func (l LabelNames) Len() int {
|
||||||
|
return len(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LabelNames) Less(i, j int) bool {
|
||||||
|
return l[i] < l[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LabelNames) Swap(i, j int) {
|
||||||
|
l[i], l[j] = l[j], l[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LabelNames) String() string {
|
||||||
|
labelStrings := make([]string, 0, len(l))
|
||||||
|
for _, label := range l {
|
||||||
|
labelStrings = append(labelStrings, string(label))
|
||||||
|
}
|
||||||
|
return strings.Join(labelStrings, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// A LabelValue is an associated value for a LabelName.
|
||||||
|
type LabelValue string
|
||||||
|
|
||||||
|
// LabelValues is a sortable LabelValue slice. It implements sort.Interface.
|
||||||
|
type LabelValues []LabelValue
|
||||||
|
|
||||||
|
func (l LabelValues) Len() int {
|
||||||
|
return len(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LabelValues) Less(i, j int) bool {
|
||||||
|
return sort.StringsAreSorted([]string{string(l[i]), string(l[j])})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LabelValues) Swap(i, j int) {
|
||||||
|
l[i], l[j] = l[j], l[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// LabelPair pairs a name with a value.
|
||||||
|
type LabelPair struct {
|
||||||
|
Name LabelName
|
||||||
|
Value LabelValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// LabelPairs is a sortable slice of LabelPair pointers. It implements
|
||||||
|
// sort.Interface.
|
||||||
|
type LabelPairs []*LabelPair
|
||||||
|
|
||||||
|
func (l LabelPairs) Len() int {
|
||||||
|
return len(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LabelPairs) Less(i, j int) bool {
|
||||||
|
switch {
|
||||||
|
case l[i].Name > l[j].Name:
|
||||||
|
return false
|
||||||
|
case l[i].Name < l[j].Name:
|
||||||
|
return true
|
||||||
|
case l[i].Value > l[j].Value:
|
||||||
|
return false
|
||||||
|
case l[i].Value < l[j].Value:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LabelPairs) Swap(i, j int) {
|
||||||
|
l[i], l[j] = l[j], l[i]
|
||||||
|
}
|
91
Godeps/_workspace/src/github.com/prometheus/common/model/labels_test.go
generated
vendored
Normal file
91
Godeps/_workspace/src/github.com/prometheus/common/model/labels_test.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testLabelNames(t testing.TB) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
in LabelNames
|
||||||
|
out LabelNames
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: LabelNames{"ZZZ", "zzz"},
|
||||||
|
out: LabelNames{"ZZZ", "zzz"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: LabelNames{"aaa", "AAA"},
|
||||||
|
out: LabelNames{"AAA", "aaa"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
sort.Sort(scenario.in)
|
||||||
|
|
||||||
|
for j, expected := range scenario.out {
|
||||||
|
if expected != scenario.in[j] {
|
||||||
|
t.Errorf("%d.%d expected %s, got %s", i, j, expected, scenario.in[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLabelNames(t *testing.T) {
|
||||||
|
testLabelNames(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLabelNames(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
testLabelNames(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLabelValues(t testing.TB) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
in LabelValues
|
||||||
|
out LabelValues
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: LabelValues{"ZZZ", "zzz"},
|
||||||
|
out: LabelValues{"ZZZ", "zzz"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: LabelValues{"aaa", "AAA"},
|
||||||
|
out: LabelValues{"AAA", "aaa"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
sort.Sort(scenario.in)
|
||||||
|
|
||||||
|
for j, expected := range scenario.out {
|
||||||
|
if expected != scenario.in[j] {
|
||||||
|
t.Errorf("%d.%d expected %s, got %s", i, j, expected, scenario.in[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLabelValues(t *testing.T) {
|
||||||
|
testLabelValues(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLabelValues(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
testLabelValues(b)
|
||||||
|
}
|
||||||
|
}
|
153
Godeps/_workspace/src/github.com/prometheus/common/model/labelset.go
generated
vendored
Normal file
153
Godeps/_workspace/src/github.com/prometheus/common/model/labelset.go
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
func (ls LabelSet) Equal(o LabelSet) bool {
|
||||||
|
if len(ls) != len(o) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for ln, lv := range ls {
|
||||||
|
olv, ok := o[ln]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if olv != lv {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before compares the metrics, using the following criteria:
|
||||||
|
//
|
||||||
|
// If m has fewer labels than o, it is before o. If it has more, it is not.
|
||||||
|
//
|
||||||
|
// If the number of labels is the same, the superset of all label names is
|
||||||
|
// sorted alphanumerically. The first differing label pair found in that order
|
||||||
|
// determines the outcome: If the label does not exist at all in m, then m is
|
||||||
|
// before o, and vice versa. Otherwise the label value is compared
|
||||||
|
// alphanumerically.
|
||||||
|
//
|
||||||
|
// If m and o are equal, the method returns false.
|
||||||
|
func (ls LabelSet) Before(o LabelSet) bool {
|
||||||
|
if len(ls) < len(o) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(ls) > len(o) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
lns := make(LabelNames, 0, len(ls)+len(o))
|
||||||
|
for ln := range ls {
|
||||||
|
lns = append(lns, ln)
|
||||||
|
}
|
||||||
|
for ln := range o {
|
||||||
|
lns = append(lns, ln)
|
||||||
|
}
|
||||||
|
// It's probably not worth it to de-dup lns.
|
||||||
|
sort.Sort(lns)
|
||||||
|
for _, ln := range lns {
|
||||||
|
mlv, ok := ls[ln]
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
olv, ok := o[ln]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if mlv < olv {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if mlv > olv {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls LabelSet) Clone() LabelSet {
|
||||||
|
lsn := make(LabelSet, len(ls))
|
||||||
|
for ln, lv := range ls {
|
||||||
|
lsn[ln] = lv
|
||||||
|
}
|
||||||
|
return lsn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge is a 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 {
|
||||||
|
lstrs := make([]string, 0, len(l))
|
||||||
|
for l, v := range l {
|
||||||
|
lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(lstrs)
|
||||||
|
return fmt.Sprintf("{%s}", strings.Join(lstrs, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fingerprint returns the LabelSet's fingerprint.
|
||||||
|
func (ls LabelSet) Fingerprint() Fingerprint {
|
||||||
|
return labelSetToFingerprint(ls)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastFingerprint returns the LabelSet's Fingerprint calculated by a faster hashing
|
||||||
|
// algorithm, which is, however, more susceptible to hash collisions.
|
||||||
|
func (ls LabelSet) FastFingerprint() Fingerprint {
|
||||||
|
return labelSetToFastFingerprint(ls)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (l *LabelSet) UnmarshalJSON(b []byte) error {
|
||||||
|
var m map[LabelName]LabelValue
|
||||||
|
if err := json.Unmarshal(b, &m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// encoding/json only unmarshals maps of the form map[string]T. It treats
|
||||||
|
// LabelName as a string and does not call its UnmarshalJSON method.
|
||||||
|
// Thus, we have to replicate the behavior here.
|
||||||
|
for ln := range m {
|
||||||
|
if !LabelNameRE.MatchString(string(ln)) {
|
||||||
|
return fmt.Errorf("%q is not a valid label name", ln)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*l = LabelSet(m)
|
||||||
|
return nil
|
||||||
|
}
|
120
Godeps/_workspace/src/github.com/prometheus/common/model/metric.go
generated
vendored
Normal file
120
Godeps/_workspace/src/github.com/prometheus/common/model/metric.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var separator = []byte{0}
|
||||||
|
|
||||||
|
// 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 LabelSet
|
||||||
|
|
||||||
|
// Equal compares the metrics.
|
||||||
|
func (m Metric) Equal(o Metric) bool {
|
||||||
|
return LabelSet(m).Equal(LabelSet(o))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before compares the metrics' underlying label sets.
|
||||||
|
func (m Metric) Before(o Metric) bool {
|
||||||
|
return LabelSet(m).Before(LabelSet(o))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone returns a copy of the Metric.
|
||||||
|
func (m Metric) Clone() Metric {
|
||||||
|
clone := Metric{}
|
||||||
|
for k, v := range m {
|
||||||
|
clone[k] = v
|
||||||
|
}
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Metric) String() string {
|
||||||
|
metricName, hasName := m[MetricNameLabel]
|
||||||
|
numLabels := len(m) - 1
|
||||||
|
if !hasName {
|
||||||
|
numLabels = len(m)
|
||||||
|
}
|
||||||
|
labelStrings := make([]string, 0, numLabels)
|
||||||
|
for label, value := range m {
|
||||||
|
if label != MetricNameLabel {
|
||||||
|
labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch numLabels {
|
||||||
|
case 0:
|
||||||
|
if hasName {
|
||||||
|
return string(metricName)
|
||||||
|
}
|
||||||
|
return "{}"
|
||||||
|
default:
|
||||||
|
sort.Strings(labelStrings)
|
||||||
|
return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fingerprint returns a Metric's Fingerprint.
|
||||||
|
func (m Metric) Fingerprint() Fingerprint {
|
||||||
|
return LabelSet(m).Fingerprint()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastFingerprint returns a Metric's Fingerprint calculated by a faster hashing
|
||||||
|
// algorithm, which is, however, more susceptible to hash collisions.
|
||||||
|
func (m Metric) FastFingerprint() Fingerprint {
|
||||||
|
return LabelSet(m).FastFingerprint()
|
||||||
|
}
|
||||||
|
|
||||||
|
// COWMetric wraps a Metric to enable copy-on-write access patterns.
|
||||||
|
type COWMetric struct {
|
||||||
|
Copied bool
|
||||||
|
Metric Metric
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets a label name in the wrapped Metric to a given value and copies the
|
||||||
|
// Metric initially, if it is not already a copy.
|
||||||
|
func (m *COWMetric) Set(ln LabelName, lv LabelValue) {
|
||||||
|
m.doCOW()
|
||||||
|
m.Metric[ln] = lv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a given label name from the wrapped Metric and copies the
|
||||||
|
// Metric initially, if it is not already a copy.
|
||||||
|
func (m *COWMetric) Del(ln LabelName) {
|
||||||
|
m.doCOW()
|
||||||
|
delete(m.Metric, ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
// doCOW copies the underlying Metric if it is not already a copy.
|
||||||
|
func (m *COWMetric) doCOW() {
|
||||||
|
if !m.Copied {
|
||||||
|
m.Metric = m.Metric.Clone()
|
||||||
|
m.Copied = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements fmt.Stringer.
|
||||||
|
func (m COWMetric) String() string {
|
||||||
|
return m.Metric.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (m COWMetric) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(m.Metric)
|
||||||
|
}
|
132
Godeps/_workspace/src/github.com/prometheus/common/model/metric_test.go
generated
vendored
Normal file
132
Godeps/_workspace/src/github.com/prometheus/common/model/metric_test.go
generated
vendored
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 "testing"
|
||||||
|
|
||||||
|
func testMetric(t testing.TB) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
input LabelSet
|
||||||
|
fingerprint Fingerprint
|
||||||
|
fastFingerprint Fingerprint
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: LabelSet{},
|
||||||
|
fingerprint: 14695981039346656037,
|
||||||
|
fastFingerprint: 14695981039346656037,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: LabelSet{
|
||||||
|
"first_name": "electro",
|
||||||
|
"occupation": "robot",
|
||||||
|
"manufacturer": "westinghouse",
|
||||||
|
},
|
||||||
|
fingerprint: 5911716720268894962,
|
||||||
|
fastFingerprint: 11310079640881077873,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: LabelSet{
|
||||||
|
"x": "y",
|
||||||
|
},
|
||||||
|
fingerprint: 8241431561484471700,
|
||||||
|
fastFingerprint: 13948396922932177635,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: LabelSet{
|
||||||
|
"a": "bb",
|
||||||
|
"b": "c",
|
||||||
|
},
|
||||||
|
fingerprint: 3016285359649981711,
|
||||||
|
fastFingerprint: 3198632812309449502,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: LabelSet{
|
||||||
|
"a": "b",
|
||||||
|
"bb": "c",
|
||||||
|
},
|
||||||
|
fingerprint: 7122421792099404749,
|
||||||
|
fastFingerprint: 5774953389407657638,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
input := Metric(scenario.input)
|
||||||
|
|
||||||
|
if scenario.fingerprint != input.Fingerprint() {
|
||||||
|
t.Errorf("%d. expected %d, got %d", i, scenario.fingerprint, input.Fingerprint())
|
||||||
|
}
|
||||||
|
if scenario.fastFingerprint != input.FastFingerprint() {
|
||||||
|
t.Errorf("%d. expected %d, got %d", i, scenario.fastFingerprint, input.FastFingerprint())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetric(t *testing.T) {
|
||||||
|
testMetric(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetric(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
testMetric(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCOWMetric(t *testing.T) {
|
||||||
|
testMetric := Metric{
|
||||||
|
"to_delete": "test1",
|
||||||
|
"to_change": "test2",
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []struct {
|
||||||
|
fn func(*COWMetric)
|
||||||
|
out Metric
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
fn: func(cm *COWMetric) {
|
||||||
|
cm.Del("to_delete")
|
||||||
|
},
|
||||||
|
out: Metric{
|
||||||
|
"to_change": "test2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fn: func(cm *COWMetric) {
|
||||||
|
cm.Set("to_change", "changed")
|
||||||
|
},
|
||||||
|
out: Metric{
|
||||||
|
"to_delete": "test1",
|
||||||
|
"to_change": "changed",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range scenarios {
|
||||||
|
orig := testMetric.Clone()
|
||||||
|
cm := &COWMetric{
|
||||||
|
Metric: orig,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.fn(cm)
|
||||||
|
|
||||||
|
// Test that the original metric was not modified.
|
||||||
|
if !orig.Equal(testMetric) {
|
||||||
|
t.Fatalf("%d. original metric changed; expected %v, got %v", i, testMetric, orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the new metric has the right changes.
|
||||||
|
if !cm.Metric.Equal(s.out) {
|
||||||
|
t.Fatalf("%d. copied metric doesn't contain expected changes; expected %v, got %v", i, s.out, cm.Metric)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
Godeps/_workspace/src/github.com/prometheus/common/model/model.go
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/prometheus/common/model/model.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 contains common data structures that are shared across
|
||||||
|
// Prometheus componenets and libraries.
|
||||||
|
package model
|
190
Godeps/_workspace/src/github.com/prometheus/common/model/signature.go
generated
vendored
Normal file
190
Godeps/_workspace/src/github.com/prometheus/common/model/signature.go
generated
vendored
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
// Copyright 2014 The Prometheus Authors
|
||||||
|
// 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"
|
||||||
|
"hash"
|
||||||
|
"hash/fnv"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is
|
||||||
|
// used to separate label names, label values, and other strings from each other
|
||||||
|
// when calculating their combined hash value (aka signature aka fingerprint).
|
||||||
|
const SeparatorByte byte = 255
|
||||||
|
|
||||||
|
var (
|
||||||
|
// cache the signature of an empty label set.
|
||||||
|
emptyLabelSignature = fnv.New64a().Sum64()
|
||||||
|
|
||||||
|
hashAndBufPool sync.Pool
|
||||||
|
)
|
||||||
|
|
||||||
|
type hashAndBuf struct {
|
||||||
|
h hash.Hash64
|
||||||
|
b bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHashAndBuf() *hashAndBuf {
|
||||||
|
hb := hashAndBufPool.Get()
|
||||||
|
if hb == nil {
|
||||||
|
return &hashAndBuf{h: fnv.New64a()}
|
||||||
|
}
|
||||||
|
return hb.(*hashAndBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putHashAndBuf(hb *hashAndBuf) {
|
||||||
|
hb.h.Reset()
|
||||||
|
hb.b.Reset()
|
||||||
|
hashAndBufPool.Put(hb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a
|
||||||
|
// given label set. (Collisions are possible but unlikely if the number of label
|
||||||
|
// sets the function is applied to is small.)
|
||||||
|
func LabelsToSignature(labels map[string]string) uint64 {
|
||||||
|
if len(labels) == 0 {
|
||||||
|
return emptyLabelSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
labelNames := make([]string, 0, len(labels))
|
||||||
|
for labelName := range labels {
|
||||||
|
labelNames = append(labelNames, labelName)
|
||||||
|
}
|
||||||
|
sort.Strings(labelNames)
|
||||||
|
|
||||||
|
hb := getHashAndBuf()
|
||||||
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
|
for _, labelName := range labelNames {
|
||||||
|
hb.b.WriteString(labelName)
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.b.WriteString(labels[labelName])
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.h.Write(hb.b.Bytes())
|
||||||
|
hb.b.Reset()
|
||||||
|
}
|
||||||
|
return hb.h.Sum64()
|
||||||
|
}
|
||||||
|
|
||||||
|
// labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as
|
||||||
|
// parameter (rather than a label map) and returns a Fingerprint.
|
||||||
|
func labelSetToFingerprint(ls LabelSet) Fingerprint {
|
||||||
|
if len(ls) == 0 {
|
||||||
|
return Fingerprint(emptyLabelSignature)
|
||||||
|
}
|
||||||
|
|
||||||
|
labelNames := make(LabelNames, 0, len(ls))
|
||||||
|
for labelName := range ls {
|
||||||
|
labelNames = append(labelNames, labelName)
|
||||||
|
}
|
||||||
|
sort.Sort(labelNames)
|
||||||
|
|
||||||
|
hb := getHashAndBuf()
|
||||||
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
|
for _, labelName := range labelNames {
|
||||||
|
hb.b.WriteString(string(labelName))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.b.WriteString(string(ls[labelName]))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.h.Write(hb.b.Bytes())
|
||||||
|
hb.b.Reset()
|
||||||
|
}
|
||||||
|
return Fingerprint(hb.h.Sum64())
|
||||||
|
}
|
||||||
|
|
||||||
|
// labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a
|
||||||
|
// faster and less allocation-heavy hash function, which is more susceptible to
|
||||||
|
// create hash collisions. Therefore, collision detection should be applied.
|
||||||
|
func labelSetToFastFingerprint(ls LabelSet) Fingerprint {
|
||||||
|
if len(ls) == 0 {
|
||||||
|
return Fingerprint(emptyLabelSignature)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result uint64
|
||||||
|
hb := getHashAndBuf()
|
||||||
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
|
for labelName, labelValue := range ls {
|
||||||
|
hb.b.WriteString(string(labelName))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.b.WriteString(string(labelValue))
|
||||||
|
hb.h.Write(hb.b.Bytes())
|
||||||
|
result ^= hb.h.Sum64()
|
||||||
|
hb.h.Reset()
|
||||||
|
hb.b.Reset()
|
||||||
|
}
|
||||||
|
return Fingerprint(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignatureForLabels works like LabelsToSignature but takes a Metric as
|
||||||
|
// parameter (rather than a label map) and only includes the labels with the
|
||||||
|
// specified LabelNames into the signature calculation. The labels passed in
|
||||||
|
// will be sorted by this function.
|
||||||
|
func SignatureForLabels(m Metric, labels ...LabelName) uint64 {
|
||||||
|
if len(m) == 0 || len(labels) == 0 {
|
||||||
|
return emptyLabelSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(LabelNames(labels))
|
||||||
|
|
||||||
|
hb := getHashAndBuf()
|
||||||
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
|
for _, label := range labels {
|
||||||
|
hb.b.WriteString(string(label))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.b.WriteString(string(m[label]))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.h.Write(hb.b.Bytes())
|
||||||
|
hb.b.Reset()
|
||||||
|
}
|
||||||
|
return hb.h.Sum64()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignatureWithoutLabels works like LabelsToSignature but takes a Metric as
|
||||||
|
// parameter (rather than a label map) and excludes the labels with any of the
|
||||||
|
// specified LabelNames from the signature calculation.
|
||||||
|
func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return emptyLabelSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
labelNames := make(LabelNames, 0, len(m))
|
||||||
|
for labelName := range m {
|
||||||
|
if _, exclude := labels[labelName]; !exclude {
|
||||||
|
labelNames = append(labelNames, labelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(labelNames) == 0 {
|
||||||
|
return emptyLabelSignature
|
||||||
|
}
|
||||||
|
sort.Sort(labelNames)
|
||||||
|
|
||||||
|
hb := getHashAndBuf()
|
||||||
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
|
for _, labelName := range labelNames {
|
||||||
|
hb.b.WriteString(string(labelName))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.b.WriteString(string(m[labelName]))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
|
hb.h.Write(hb.b.Bytes())
|
||||||
|
hb.b.Reset()
|
||||||
|
}
|
||||||
|
return hb.h.Sum64()
|
||||||
|
}
|
304
Godeps/_workspace/src/github.com/prometheus/common/model/signature_test.go
generated
vendored
Normal file
304
Godeps/_workspace/src/github.com/prometheus/common/model/signature_test.go
generated
vendored
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
// Copyright 2014 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLabelsToSignature(t *testing.T) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
in map[string]string
|
||||||
|
out uint64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: map[string]string{},
|
||||||
|
out: 14695981039346656037,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: map[string]string{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
out: 5799056148416392346,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
actual := LabelsToSignature(scenario.in)
|
||||||
|
|
||||||
|
if actual != scenario.out {
|
||||||
|
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetricToFingerprint(t *testing.T) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
in LabelSet
|
||||||
|
out Fingerprint
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: LabelSet{},
|
||||||
|
out: 14695981039346656037,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: LabelSet{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
out: 5799056148416392346,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
actual := labelSetToFingerprint(scenario.in)
|
||||||
|
|
||||||
|
if actual != scenario.out {
|
||||||
|
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetricToFastFingerprint(t *testing.T) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
in LabelSet
|
||||||
|
out Fingerprint
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: LabelSet{},
|
||||||
|
out: 14695981039346656037,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: LabelSet{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
out: 12952432476264840823,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
actual := labelSetToFastFingerprint(scenario.in)
|
||||||
|
|
||||||
|
if actual != scenario.out {
|
||||||
|
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSignatureForLabels(t *testing.T) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
in Metric
|
||||||
|
labels LabelNames
|
||||||
|
out uint64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: Metric{},
|
||||||
|
labels: nil,
|
||||||
|
out: 14695981039346656037,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
labels: LabelNames{"fear", "name"},
|
||||||
|
out: 5799056148416392346,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
|
||||||
|
labels: LabelNames{"fear", "name"},
|
||||||
|
out: 5799056148416392346,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
labels: LabelNames{},
|
||||||
|
out: 14695981039346656037,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
labels: nil,
|
||||||
|
out: 14695981039346656037,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
actual := SignatureForLabels(scenario.in, scenario.labels...)
|
||||||
|
|
||||||
|
if actual != scenario.out {
|
||||||
|
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSignatureWithoutLabels(t *testing.T) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
in Metric
|
||||||
|
labels map[LabelName]struct{}
|
||||||
|
out uint64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: Metric{},
|
||||||
|
labels: nil,
|
||||||
|
out: 14695981039346656037,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
labels: map[LabelName]struct{}{"fear": struct{}{}, "name": struct{}{}},
|
||||||
|
out: 14695981039346656037,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
|
||||||
|
labels: map[LabelName]struct{}{"foo": struct{}{}},
|
||||||
|
out: 5799056148416392346,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
labels: map[LabelName]struct{}{},
|
||||||
|
out: 5799056148416392346,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
|
labels: nil,
|
||||||
|
out: 5799056148416392346,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
actual := SignatureWithoutLabels(scenario.in, scenario.labels)
|
||||||
|
|
||||||
|
if actual != scenario.out {
|
||||||
|
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkLabelToSignature(b *testing.B, l map[string]string, e uint64) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if a := LabelsToSignature(l); a != e {
|
||||||
|
b.Fatalf("expected signature of %d for %s, got %d", e, l, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLabelToSignatureScalar(b *testing.B) {
|
||||||
|
benchmarkLabelToSignature(b, nil, 14695981039346656037)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLabelToSignatureSingle(b *testing.B) {
|
||||||
|
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value"}, 5146282821936882169)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLabelToSignatureDouble(b *testing.B) {
|
||||||
|
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLabelToSignatureTriple(b *testing.B) {
|
||||||
|
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121)
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkMetricToFingerprint(b *testing.B, ls LabelSet, e Fingerprint) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if a := labelSetToFingerprint(ls); a != e {
|
||||||
|
b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFingerprintScalar(b *testing.B) {
|
||||||
|
benchmarkMetricToFingerprint(b, nil, 14695981039346656037)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFingerprintSingle(b *testing.B) {
|
||||||
|
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5146282821936882169)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFingerprintDouble(b *testing.B) {
|
||||||
|
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFingerprintTriple(b *testing.B) {
|
||||||
|
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121)
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkMetricToFastFingerprint(b *testing.B, ls LabelSet, e Fingerprint) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if a := labelSetToFastFingerprint(ls); a != e {
|
||||||
|
b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFastFingerprintScalar(b *testing.B) {
|
||||||
|
benchmarkMetricToFastFingerprint(b, nil, 14695981039346656037)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFastFingerprintSingle(b *testing.B) {
|
||||||
|
benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5147259542624943964)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFastFingerprintDouble(b *testing.B) {
|
||||||
|
benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 18269973311206963528)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFastFingerprintTriple(b *testing.B) {
|
||||||
|
benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyLabelSignature(t *testing.T) {
|
||||||
|
input := []map[string]string{nil, {}}
|
||||||
|
|
||||||
|
var ms runtime.MemStats
|
||||||
|
runtime.ReadMemStats(&ms)
|
||||||
|
|
||||||
|
alloc := ms.Alloc
|
||||||
|
|
||||||
|
for _, labels := range input {
|
||||||
|
LabelsToSignature(labels)
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime.ReadMemStats(&ms)
|
||||||
|
|
||||||
|
if got := ms.Alloc; alloc != got {
|
||||||
|
t.Fatal("expected LabelsToSignature with empty labels not to perform allocations")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkMetricToFastFingerprintConc(b *testing.B, ls LabelSet, e Fingerprint, concLevel int) {
|
||||||
|
var start, end sync.WaitGroup
|
||||||
|
start.Add(1)
|
||||||
|
end.Add(concLevel)
|
||||||
|
|
||||||
|
for i := 0; i < concLevel; i++ {
|
||||||
|
go func() {
|
||||||
|
start.Wait()
|
||||||
|
for j := b.N / concLevel; j >= 0; j-- {
|
||||||
|
if a := labelSetToFastFingerprint(ls); a != e {
|
||||||
|
b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
start.Done()
|
||||||
|
end.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFastFingerprintTripleConc1(b *testing.B) {
|
||||||
|
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFastFingerprintTripleConc2(b *testing.B) {
|
||||||
|
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFastFingerprintTripleConc4(b *testing.B) {
|
||||||
|
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFastFingerprintTripleConc8(b *testing.B) {
|
||||||
|
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 8)
|
||||||
|
}
|
232
Godeps/_workspace/src/github.com/prometheus/common/model/time.go
generated
vendored
Normal file
232
Godeps/_workspace/src/github.com/prometheus/common/model/time.go
generated
vendored
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MinimumTick is the minimum supported time resolution. This has to be
|
||||||
|
// at least time.Second in order for the code below to work.
|
||||||
|
minimumTick = time.Millisecond
|
||||||
|
// second is the Time duration equivalent to one second.
|
||||||
|
second = int64(time.Second / minimumTick)
|
||||||
|
// The number of nanoseconds per minimum tick.
|
||||||
|
nanosPerTick = int64(minimumTick / time.Nanosecond)
|
||||||
|
|
||||||
|
// Earliest is the earliest Time representable. Handy for
|
||||||
|
// initializing a high watermark.
|
||||||
|
Earliest = Time(math.MinInt64)
|
||||||
|
// Latest is the latest Time representable. Handy for initializing
|
||||||
|
// a low watermark.
|
||||||
|
Latest = Time(math.MaxInt64)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Time is the number of milliseconds since the epoch
|
||||||
|
// (1970-01-01 00:00 UTC) excluding leap seconds.
|
||||||
|
type Time int64
|
||||||
|
|
||||||
|
// Interval describes and interval between two timestamps.
|
||||||
|
type Interval struct {
|
||||||
|
Start, End Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now returns the current time as a Time.
|
||||||
|
func Now() Time {
|
||||||
|
return TimeFromUnixNano(time.Now().UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeFromUnix returns the Time equivalent to the Unix Time t
|
||||||
|
// provided in seconds.
|
||||||
|
func TimeFromUnix(t int64) Time {
|
||||||
|
return Time(t * second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeFromUnixNano returns the Time equivalent to the Unix Time
|
||||||
|
// t provided in nanoseconds.
|
||||||
|
func TimeFromUnixNano(t int64) Time {
|
||||||
|
return Time(t / nanosPerTick)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal reports whether two Times represent the same instant.
|
||||||
|
func (t Time) Equal(o Time) bool {
|
||||||
|
return t == o
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before reports whether the Time t is before o.
|
||||||
|
func (t Time) Before(o Time) bool {
|
||||||
|
return t < o
|
||||||
|
}
|
||||||
|
|
||||||
|
// After reports whether the Time t is after o.
|
||||||
|
func (t Time) After(o Time) bool {
|
||||||
|
return t > o
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add returns the Time t + d.
|
||||||
|
func (t Time) Add(d time.Duration) Time {
|
||||||
|
return t + Time(d/minimumTick)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub returns the Duration t - o.
|
||||||
|
func (t Time) Sub(o Time) time.Duration {
|
||||||
|
return time.Duration(t-o) * minimumTick
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time returns the time.Time representation of t.
|
||||||
|
func (t Time) Time() time.Time {
|
||||||
|
return time.Unix(int64(t)/second, (int64(t)%second)*nanosPerTick)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unix returns t as a Unix time, the number of seconds elapsed
|
||||||
|
// since January 1, 1970 UTC.
|
||||||
|
func (t Time) Unix() int64 {
|
||||||
|
return int64(t) / second
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
|
||||||
|
// since January 1, 1970 UTC.
|
||||||
|
func (t Time) UnixNano() int64 {
|
||||||
|
return int64(t) * nanosPerTick
|
||||||
|
}
|
||||||
|
|
||||||
|
// The number of digits after the dot.
|
||||||
|
var dotPrecision = int(math.Log10(float64(second)))
|
||||||
|
|
||||||
|
// String returns a string representation of the Time.
|
||||||
|
func (t Time) String() string {
|
||||||
|
s := strconv.FormatInt(int64(t), 10)
|
||||||
|
i := len(s) - dotPrecision
|
||||||
|
return s[:i] + "." + s[i:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
|
func (t Time) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(t.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (t *Time) UnmarshalJSON(b []byte) error {
|
||||||
|
p := strings.Split(string(b), ".")
|
||||||
|
switch len(p) {
|
||||||
|
case 1:
|
||||||
|
v, err := strconv.ParseInt(string(p[0]), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = Time(v * second)
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
v, err := strconv.ParseInt(string(p[0]), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v *= second
|
||||||
|
|
||||||
|
prec := dotPrecision - len(p[1])
|
||||||
|
if prec < 0 {
|
||||||
|
p[1] = p[1][:dotPrecision]
|
||||||
|
} else if prec > 0 {
|
||||||
|
p[1] = p[1] + strings.Repeat("0", prec)
|
||||||
|
}
|
||||||
|
|
||||||
|
va, err := strconv.ParseInt(p[1], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = Time(v + va)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid time %q", string(b))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration wraps time.Duration. It is used to parse the custom duration format
|
||||||
|
// from YAML.
|
||||||
|
// This type should not propagate beyond the scope of input/output processing.
|
||||||
|
type Duration time.Duration
|
||||||
|
|
||||||
|
// StringToDuration parses a string into a time.Duration, assuming that a year
|
||||||
|
// a day always has 24h.
|
||||||
|
func ParseDuration(durationStr string) (Duration, error) {
|
||||||
|
matches := durationRE.FindStringSubmatch(durationStr)
|
||||||
|
if len(matches) != 3 {
|
||||||
|
return 0, fmt.Errorf("not a valid duration string: %q", durationStr)
|
||||||
|
}
|
||||||
|
durSeconds, _ := strconv.Atoi(matches[1])
|
||||||
|
dur := time.Duration(durSeconds) * time.Second
|
||||||
|
unit := matches[2]
|
||||||
|
switch unit {
|
||||||
|
case "d":
|
||||||
|
dur *= 60 * 60 * 24
|
||||||
|
case "h":
|
||||||
|
dur *= 60 * 60
|
||||||
|
case "m":
|
||||||
|
dur *= 60
|
||||||
|
case "s":
|
||||||
|
dur *= 1
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("invalid time unit in duration string: %q", unit)
|
||||||
|
}
|
||||||
|
return Duration(dur), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var durationRE = regexp.MustCompile("^([0-9]+)([ywdhms]+)$")
|
||||||
|
|
||||||
|
func (d Duration) String() string {
|
||||||
|
seconds := int64(time.Duration(d) / time.Second)
|
||||||
|
factors := map[string]int64{
|
||||||
|
"d": 60 * 60 * 24,
|
||||||
|
"h": 60 * 60,
|
||||||
|
"m": 60,
|
||||||
|
"s": 1,
|
||||||
|
}
|
||||||
|
unit := "s"
|
||||||
|
switch int64(0) {
|
||||||
|
case seconds % factors["d"]:
|
||||||
|
unit = "d"
|
||||||
|
case seconds % factors["h"]:
|
||||||
|
unit = "h"
|
||||||
|
case seconds % factors["m"]:
|
||||||
|
unit = "m"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v%v", seconds/factors[unit], unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalYAML implements the yaml.Marshaler interface.
|
||||||
|
func (d Duration) MarshalYAML() (interface{}, error) {
|
||||||
|
return d.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
var s string
|
||||||
|
if err := unmarshal(&s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dur, err := ParseDuration(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*d = dur
|
||||||
|
return nil
|
||||||
|
}
|
86
Godeps/_workspace/src/github.com/prometheus/common/model/time_test.go
generated
vendored
Normal file
86
Godeps/_workspace/src/github.com/prometheus/common/model/time_test.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestComparators(t *testing.T) {
|
||||||
|
t1a := TimeFromUnix(0)
|
||||||
|
t1b := TimeFromUnix(0)
|
||||||
|
t2 := TimeFromUnix(2*second - 1)
|
||||||
|
|
||||||
|
if !t1a.Equal(t1b) {
|
||||||
|
t.Fatalf("Expected %s to be equal to %s", t1a, t1b)
|
||||||
|
}
|
||||||
|
if t1a.Equal(t2) {
|
||||||
|
t.Fatalf("Expected %s to not be equal to %s", t1a, t2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !t1a.Before(t2) {
|
||||||
|
t.Fatalf("Expected %s to be before %s", t1a, t2)
|
||||||
|
}
|
||||||
|
if t1a.Before(t1b) {
|
||||||
|
t.Fatalf("Expected %s to not be before %s", t1a, t1b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !t2.After(t1a) {
|
||||||
|
t.Fatalf("Expected %s to be after %s", t2, t1a)
|
||||||
|
}
|
||||||
|
if t1b.After(t1a) {
|
||||||
|
t.Fatalf("Expected %s to not be after %s", t1b, t1a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeConversions(t *testing.T) {
|
||||||
|
unixSecs := int64(1136239445)
|
||||||
|
unixNsecs := int64(123456789)
|
||||||
|
unixNano := unixSecs*1e9 + unixNsecs
|
||||||
|
|
||||||
|
t1 := time.Unix(unixSecs, unixNsecs-unixNsecs%nanosPerTick)
|
||||||
|
t2 := time.Unix(unixSecs, unixNsecs)
|
||||||
|
|
||||||
|
ts := TimeFromUnixNano(unixNano)
|
||||||
|
if !ts.Time().Equal(t1) {
|
||||||
|
t.Fatalf("Expected %s, got %s", t1, ts.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test available precision.
|
||||||
|
ts = TimeFromUnixNano(t2.UnixNano())
|
||||||
|
if !ts.Time().Equal(t1) {
|
||||||
|
t.Fatalf("Expected %s, got %s", t1, ts.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
if ts.UnixNano() != unixNano-unixNano%nanosPerTick {
|
||||||
|
t.Fatalf("Expected %d, got %d", unixNano, ts.UnixNano())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuration(t *testing.T) {
|
||||||
|
duration := time.Second + time.Minute + time.Hour
|
||||||
|
goTime := time.Unix(1136239445, 0)
|
||||||
|
|
||||||
|
ts := TimeFromUnix(goTime.Unix())
|
||||||
|
if !goTime.Add(duration).Equal(ts.Add(duration).Time()) {
|
||||||
|
t.Fatalf("Expected %s to be equal to %s", goTime.Add(duration), ts.Add(duration))
|
||||||
|
}
|
||||||
|
|
||||||
|
earlier := ts.Add(-duration)
|
||||||
|
delta := ts.Sub(earlier)
|
||||||
|
if delta != duration {
|
||||||
|
t.Fatalf("Expected %s to be equal to %s", delta, duration)
|
||||||
|
}
|
||||||
|
}
|
326
Godeps/_workspace/src/github.com/prometheus/common/model/value.go
generated
vendored
Normal file
326
Godeps/_workspace/src/github.com/prometheus/common/model/value.go
generated
vendored
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A SampleValue is a representation of a value for a given sample at a given
|
||||||
|
// time.
|
||||||
|
type SampleValue float64
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (v SampleValue) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(v.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (v *SampleValue) UnmarshalJSON(b []byte) error {
|
||||||
|
if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
|
||||||
|
return fmt.Errorf("sample value must be a quoted string")
|
||||||
|
}
|
||||||
|
f, err := strconv.ParseFloat(string(b[1:len(b)-1]), 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*v = SampleValue(f)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v SampleValue) Equal(o SampleValue) bool {
|
||||||
|
return v == o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v SampleValue) String() string {
|
||||||
|
return strconv.FormatFloat(float64(v), 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SamplePair pairs a SampleValue with a Timestamp.
|
||||||
|
type SamplePair struct {
|
||||||
|
Timestamp Time
|
||||||
|
Value SampleValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (s SamplePair) MarshalJSON() ([]byte, error) {
|
||||||
|
t, err := json.Marshal(s.Timestamp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v, err := json.Marshal(s.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return json.Marshal([...]interface{}{t, v})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (s *SamplePair) UnmarshalJSON(b []byte) error {
|
||||||
|
if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
|
||||||
|
return fmt.Errorf("sample pair must be array")
|
||||||
|
}
|
||||||
|
|
||||||
|
b = b[1 : len(b)-1]
|
||||||
|
|
||||||
|
return json.Unmarshal(b, [...]json.Unmarshaler{&s.Timestamp, &s.Value})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns true if this SamplePair and o have equal Values and equal
|
||||||
|
// Timestamps.
|
||||||
|
func (s *SamplePair) Equal(o *SamplePair) bool {
|
||||||
|
return s == o || (s.Value == o.Value && s.Timestamp.Equal(o.Timestamp))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SamplePair) String() string {
|
||||||
|
return fmt.Sprintf("%s @[%s]", s.Value, s.Timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sample is a sample pair associated with a metric.
|
||||||
|
type Sample struct {
|
||||||
|
Metric Metric
|
||||||
|
Value SampleValue
|
||||||
|
Timestamp Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal compares first the metrics, then the timestamp, then the value.
|
||||||
|
func (s *Sample) Equal(o *Sample) bool {
|
||||||
|
if s == o {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.Metric.Equal(o.Metric) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !s.Timestamp.Equal(o.Timestamp) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if s.Value != o.Value {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Sample) String() string {
|
||||||
|
return fmt.Sprintf("%s => %s", s.Metric, SamplePair{
|
||||||
|
Timestamp: s.Timestamp,
|
||||||
|
Value: s.Value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samples is a sortable Sample slice. It implements sort.Interface.
|
||||||
|
type Samples []*Sample
|
||||||
|
|
||||||
|
func (s Samples) Len() int {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less compares first the metrics, then the timestamp.
|
||||||
|
func (s Samples) Less(i, j int) bool {
|
||||||
|
switch {
|
||||||
|
case s[i].Metric.Before(s[j].Metric):
|
||||||
|
return true
|
||||||
|
case s[j].Metric.Before(s[i].Metric):
|
||||||
|
return false
|
||||||
|
case s[i].Timestamp.Before(s[j].Timestamp):
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Samples) Swap(i, j int) {
|
||||||
|
s[i], s[j] = s[j], s[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal compares two sets of samples and returns true if they are equal.
|
||||||
|
func (s Samples) Equal(o Samples) bool {
|
||||||
|
if len(s) != len(o) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, sample := range s {
|
||||||
|
if !sample.Equal(o[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SampleStream is a stream of Values belonging to an attached COWMetric.
|
||||||
|
type SampleStream struct {
|
||||||
|
Metric Metric `json:"metric"`
|
||||||
|
Values []SamplePair `json:"values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SampleStream) String() string {
|
||||||
|
vals := make([]string, len(ss.Values))
|
||||||
|
for i, v := range ss.Values {
|
||||||
|
vals[i] = v.String()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s =>\n%s", ss.Metric, strings.Join(vals, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value is a generic interface for values resulting from a query evaluation.
|
||||||
|
type Value interface {
|
||||||
|
Type() ValueType
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Matrix) Type() ValueType { return ValMatrix }
|
||||||
|
func (Vector) Type() ValueType { return ValVector }
|
||||||
|
func (*Scalar) Type() ValueType { return ValScalar }
|
||||||
|
func (*String) Type() ValueType { return ValString }
|
||||||
|
|
||||||
|
type ValueType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ValNone ValueType = iota
|
||||||
|
ValScalar
|
||||||
|
ValVector
|
||||||
|
ValMatrix
|
||||||
|
ValString
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (et ValueType) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(et.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (et *ValueType) UnmarshalJSON(b []byte) error {
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(b, &s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch s {
|
||||||
|
case "<ValNone>":
|
||||||
|
*et = ValNone
|
||||||
|
case "scalar":
|
||||||
|
*et = ValScalar
|
||||||
|
case "vector":
|
||||||
|
*et = ValVector
|
||||||
|
case "matrix":
|
||||||
|
*et = ValMatrix
|
||||||
|
case "string":
|
||||||
|
*et = ValString
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown value type %q", s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ValueType) String() string {
|
||||||
|
switch e {
|
||||||
|
case ValNone:
|
||||||
|
return "<ValNone>"
|
||||||
|
case ValScalar:
|
||||||
|
return "scalar"
|
||||||
|
case ValVector:
|
||||||
|
return "vector"
|
||||||
|
case ValMatrix:
|
||||||
|
return "matrix"
|
||||||
|
case ValString:
|
||||||
|
return "string"
|
||||||
|
}
|
||||||
|
panic("ValueType.String: unhandled value type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scalar is a scalar value evaluated at the set timestamp.
|
||||||
|
type Scalar struct {
|
||||||
|
Value SampleValue `json:"value"`
|
||||||
|
Timestamp Time `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scalar) String() string {
|
||||||
|
return fmt.Sprintf("scalar: %v @[%v]", s.Value, s.Timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is a string value evaluated at the set timestamp.
|
||||||
|
type String struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
Timestamp Time `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *String) String() string {
|
||||||
|
return s.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vector is basically only an alias for Samples, but the
|
||||||
|
// contract is that in a Vector, all Samples have the same timestamp.
|
||||||
|
type Vector []*Sample
|
||||||
|
|
||||||
|
func (vec Vector) String() string {
|
||||||
|
entries := make([]string, len(vec))
|
||||||
|
for i, s := range vec {
|
||||||
|
entries[i] = s.String()
|
||||||
|
}
|
||||||
|
return strings.Join(entries, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vec Vector) Len() int { return len(vec) }
|
||||||
|
func (vec Vector) Swap(i, j int) { vec[i], vec[j] = vec[j], vec[i] }
|
||||||
|
|
||||||
|
// Less compares first the metrics, then the timestamp.
|
||||||
|
func (vec Vector) Less(i, j int) bool {
|
||||||
|
switch {
|
||||||
|
case vec[i].Metric.Before(vec[j].Metric):
|
||||||
|
return true
|
||||||
|
case vec[j].Metric.Before(vec[i].Metric):
|
||||||
|
return false
|
||||||
|
case vec[i].Timestamp.Before(vec[j].Timestamp):
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal compares two sets of samples and returns true if they are equal.
|
||||||
|
func (vec Vector) Equal(o Vector) bool {
|
||||||
|
if len(vec) != len(o) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, sample := range vec {
|
||||||
|
if !sample.Equal(o[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matrix is a list of time series.
|
||||||
|
type Matrix []*SampleStream
|
||||||
|
|
||||||
|
func (m Matrix) Len() int { return len(m) }
|
||||||
|
func (m Matrix) Less(i, j int) bool { return m[i].Metric.Before(m[j].Metric) }
|
||||||
|
func (m Matrix) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||||
|
|
||||||
|
func (mat Matrix) String() string {
|
||||||
|
matCp := make(Matrix, len(mat))
|
||||||
|
copy(matCp, mat)
|
||||||
|
sort.Sort(matCp)
|
||||||
|
|
||||||
|
strs := make([]string, len(matCp))
|
||||||
|
|
||||||
|
for i, ss := range matCp {
|
||||||
|
strs[i] = ss.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(strs, "\n")
|
||||||
|
}
|
114
Godeps/_workspace/src/github.com/prometheus/common/model/value_test.go
generated
vendored
Normal file
114
Godeps/_workspace/src/github.com/prometheus/common/model/value_test.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
// Copyright 2013 The Prometheus Authors
|
||||||
|
// 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 (
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVectorSort(t *testing.T) {
|
||||||
|
input := Vector{
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "A",
|
||||||
|
},
|
||||||
|
Timestamp: 1,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "A",
|
||||||
|
},
|
||||||
|
Timestamp: 2,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "C",
|
||||||
|
},
|
||||||
|
Timestamp: 1,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "C",
|
||||||
|
},
|
||||||
|
Timestamp: 2,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "B",
|
||||||
|
},
|
||||||
|
Timestamp: 1,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "B",
|
||||||
|
},
|
||||||
|
Timestamp: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := Vector{
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "A",
|
||||||
|
},
|
||||||
|
Timestamp: 1,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "A",
|
||||||
|
},
|
||||||
|
Timestamp: 2,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "B",
|
||||||
|
},
|
||||||
|
Timestamp: 1,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "B",
|
||||||
|
},
|
||||||
|
Timestamp: 2,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "C",
|
||||||
|
},
|
||||||
|
Timestamp: 1,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "C",
|
||||||
|
},
|
||||||
|
Timestamp: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(input)
|
||||||
|
|
||||||
|
for i, actual := range input {
|
||||||
|
actualFp := actual.Metric.Fingerprint()
|
||||||
|
expectedFp := expected[i].Metric.Fingerprint()
|
||||||
|
|
||||||
|
if actualFp != expectedFp {
|
||||||
|
t.Fatalf("%d. Incorrect fingerprint. Got %s; want %s", i, actualFp.String(), expectedFp.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual.Timestamp != expected[i].Timestamp {
|
||||||
|
t.Fatalf("%d. Incorrect timestamp. Got %s; want %s", i, actual.Timestamp, expected[i].Timestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue