mirror of
https://github.com/prometheus/prometheus
synced 2024-12-27 00:53:12 +00: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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// XXX: Re-evaluate down the road.
|
||||
reservedDelimiter = '"'
|
||||
)
|
||||
|
||||
// A Fingerprint is a simplified representation of an entity---e.g., a hash of
|
||||
// an entire Metric.
|
||||
type Fingerprint string
|
||||
@ -40,6 +49,30 @@ type LabelSet map[LabelName]LabelValue
|
||||
// a singleton and refers to one and only one stream of samples.
|
||||
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
|
||||
// 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
|
||||
|
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 New Issue
Block a user