Merge pull request #65 from prometheus/feature/storage/rethinking

Create initial Metric fingerprinter.
This commit is contained in:
juliusv 2013-02-08 04:23:35 -08:00
commit 766a8e19d6
2 changed files with 94 additions and 0 deletions

View file

@ -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
View 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)
}