mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-09 23:24:05 -08:00
Merge pull request #65 from prometheus/feature/storage/rethinking
Create initial Metric fingerprinter.
This commit is contained in:
commit
766a8e19d6
|
@ -14,10 +14,19 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// XXX: Re-evaluate down the road.
|
||||||
|
reservedDelimiter = '"'
|
||||||
|
)
|
||||||
|
|
||||||
// A Fingerprint is a simplified representation of an entity---e.g., a hash of
|
// A Fingerprint is a simplified representation of an entity---e.g., a hash of
|
||||||
// an entire Metric.
|
// an entire Metric.
|
||||||
type Fingerprint string
|
type Fingerprint string
|
||||||
|
@ -40,6 +49,30 @@ type LabelSet map[LabelName]LabelValue
|
||||||
// a singleton and refers to one and only one stream of samples.
|
// a singleton and refers to one and only one stream of samples.
|
||||||
type Metric map[LabelName]LabelValue
|
type Metric map[LabelName]LabelValue
|
||||||
|
|
||||||
|
// Fingerprint generates a fingerprint for this given Metric.
|
||||||
|
func (m Metric) Fingerprint() string {
|
||||||
|
labelLength := len(m)
|
||||||
|
labelNames := make([]string, 0, labelLength)
|
||||||
|
|
||||||
|
for labelName := range m {
|
||||||
|
labelNames = append(labelNames, string(labelName))
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(labelNames)
|
||||||
|
|
||||||
|
summer := md5.New()
|
||||||
|
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
for _, labelName := range labelNames {
|
||||||
|
buffer.WriteString(labelName)
|
||||||
|
buffer.WriteRune(reservedDelimiter)
|
||||||
|
buffer.WriteString(string(m[LabelName(labelName)]))
|
||||||
|
}
|
||||||
|
summer.Write(buffer.Bytes())
|
||||||
|
|
||||||
|
return hex.EncodeToString(summer.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
// A SampleValue is a representation of a value for a given sample at a given
|
// A SampleValue is a representation of a value for a given sample at a given
|
||||||
// time. It is presently float32 due to that being the representation that
|
// time. It is presently float32 due to that being the representation that
|
||||||
// Protocol Buffers provide of floats in Go. This is a smell and should be
|
// Protocol Buffers provide of floats in Go. This is a smell and should be
|
||||||
|
|
61
model/metric_test.go
Normal file
61
model/metric_test.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// 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 (
|
||||||
|
"github.com/prometheus/prometheus/utility/test"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testMetric(t test.Tester) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
input map[string]string
|
||||||
|
output string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: map[string]string{},
|
||||||
|
output: "d41d8cd98f00b204e9800998ecf8427e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: map[string]string{
|
||||||
|
"first_name": "electro",
|
||||||
|
"occupation": "robot",
|
||||||
|
"manufacturer": "westinghouse",
|
||||||
|
},
|
||||||
|
output: "18596f03fce001153495d903b8b577c0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
metric := Metric{}
|
||||||
|
for key, value := range scenario.input {
|
||||||
|
metric[LabelName(key)] = LabelValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := scenario.output
|
||||||
|
actual := metric.Fingerprint()
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("%d. expected %s, got %s", i, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetric(t *testing.T) {
|
||||||
|
testMetric(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetric(b *testing.B) {
|
||||||
|
testMetric(b)
|
||||||
|
}
|
Loading…
Reference in a new issue