Merge pull request #14202 from timstclair/prometheus
Update prometheus library usage
This commit is contained in:
27
Godeps/Godeps.json
generated
27
Godeps/Godeps.json
generated
@@ -454,31 +454,24 @@
|
|||||||
"ImportPath": "github.com/pborman/uuid",
|
"ImportPath": "github.com/pborman/uuid",
|
||||||
"Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4"
|
"Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/prometheus/client_golang/extraction",
|
|
||||||
"Comment": "0.4.0-1-g692492e",
|
|
||||||
"Rev": "692492e54b553a81013254cc1fba4b6dd76fad30"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/prometheus/client_golang/model",
|
|
||||||
"Comment": "0.4.0-1-g692492e",
|
|
||||||
"Rev": "692492e54b553a81013254cc1fba4b6dd76fad30"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/prometheus/client_golang/prometheus",
|
"ImportPath": "github.com/prometheus/client_golang/prometheus",
|
||||||
"Comment": "0.4.0-1-g692492e",
|
"Comment": "0.7.0-39-g3b78d7a",
|
||||||
"Rev": "692492e54b553a81013254cc1fba4b6dd76fad30"
|
"Rev": "3b78d7a77f51ccbc364d4bc170920153022cfd08"
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/prometheus/client_golang/text",
|
|
||||||
"Comment": "0.4.0-1-g692492e",
|
|
||||||
"Rev": "692492e54b553a81013254cc1fba4b6dd76fad30"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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",
|
||||||
"Rev": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6"
|
"Rev": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/prometheus/common/expfmt",
|
||||||
|
"Rev": "53cc5b7aea4df4e69c1b9d71fca97d43b416a3ad"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/prometheus/common/model",
|
||||||
|
"Rev": "53cc5b7aea4df4e69c1b9d71fca97d43b416a3ad"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/prometheus/procfs",
|
"ImportPath": "github.com/prometheus/procfs",
|
||||||
"Rev": "490cc6eb5fa45bf8a8b7b73c8bc82a8160e8531d"
|
"Rev": "490cc6eb5fa45bf8a8b7b73c8bc82a8160e8531d"
|
||||||
|
74
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/discriminator.go
generated
vendored
74
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/discriminator.go
generated
vendored
@@ -1,74 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProcessorForRequestHeader interprets a HTTP request header to determine
|
|
||||||
// what Processor should be used for the given input. If no acceptable
|
|
||||||
// Processor can be found, an error is returned.
|
|
||||||
func ProcessorForRequestHeader(header http.Header) (Processor, error) {
|
|
||||||
if header == nil {
|
|
||||||
return nil, errors.New("received illegal and nil header")
|
|
||||||
}
|
|
||||||
|
|
||||||
mediatype, params, err := mime.ParseMediaType(header.Get("Content-Type"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid Content-Type header %q: %s", header.Get("Content-Type"), err)
|
|
||||||
}
|
|
||||||
switch mediatype {
|
|
||||||
case "application/vnd.google.protobuf":
|
|
||||||
if params["proto"] != "io.prometheus.client.MetricFamily" {
|
|
||||||
return nil, fmt.Errorf("unrecognized protocol message %s", params["proto"])
|
|
||||||
}
|
|
||||||
if params["encoding"] != "delimited" {
|
|
||||||
return nil, fmt.Errorf("unsupported encoding %s", params["encoding"])
|
|
||||||
}
|
|
||||||
return MetricFamilyProcessor, nil
|
|
||||||
case "text/plain":
|
|
||||||
switch params["version"] {
|
|
||||||
case "0.0.4":
|
|
||||||
return Processor004, nil
|
|
||||||
case "":
|
|
||||||
// Fallback: most recent version.
|
|
||||||
return Processor004, nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unrecognized API version %s", params["version"])
|
|
||||||
}
|
|
||||||
case "application/json":
|
|
||||||
var prometheusAPIVersion string
|
|
||||||
|
|
||||||
if params["schema"] == "prometheus/telemetry" && params["version"] != "" {
|
|
||||||
prometheusAPIVersion = params["version"]
|
|
||||||
} else {
|
|
||||||
prometheusAPIVersion = header.Get("X-Prometheus-API-Version")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch prometheusAPIVersion {
|
|
||||||
case "0.0.2":
|
|
||||||
return Processor002, nil
|
|
||||||
case "0.0.1":
|
|
||||||
return Processor001, nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unrecognized API version %s", prometheusAPIVersion)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported media type %q, expected %q", mediatype, "application/json")
|
|
||||||
}
|
|
||||||
}
|
|
126
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/discriminator_test.go
generated
vendored
126
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/discriminator_test.go
generated
vendored
@@ -1,126 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func testDiscriminatorHTTPHeader(t testing.TB) {
|
|
||||||
var scenarios = []struct {
|
|
||||||
input map[string]string
|
|
||||||
output Processor
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
output: nil,
|
|
||||||
err: errors.New("received illegal and nil header"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": "application/json", "X-Prometheus-API-Version": "0.0.0"},
|
|
||||||
output: nil,
|
|
||||||
err: errors.New("unrecognized API version 0.0.0"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": "application/json", "X-Prometheus-API-Version": "0.0.1"},
|
|
||||||
output: Processor001,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `application/json; schema="prometheus/telemetry"; version=0.0.0`},
|
|
||||||
output: nil,
|
|
||||||
err: errors.New("unrecognized API version 0.0.0"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `application/json; schema="prometheus/telemetry"; version=0.0.1`},
|
|
||||||
output: Processor001,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `application/json; schema="prometheus/telemetry"; version=0.0.2`},
|
|
||||||
output: Processor002,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`},
|
|
||||||
output: MetricFamilyProcessor,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`},
|
|
||||||
output: nil,
|
|
||||||
err: errors.New("unrecognized protocol message illegal"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`},
|
|
||||||
output: nil,
|
|
||||||
err: errors.New("unsupported encoding illegal"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `text/plain; version=0.0.4`},
|
|
||||||
output: Processor004,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `text/plain`},
|
|
||||||
output: Processor004,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: map[string]string{"Content-Type": `text/plain; version=0.0.3`},
|
|
||||||
output: nil,
|
|
||||||
err: errors.New("unrecognized API version 0.0.3"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
|
||||||
var header http.Header
|
|
||||||
|
|
||||||
if len(scenario.input) > 0 {
|
|
||||||
header = http.Header{}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range scenario.input {
|
|
||||||
header.Add(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
actual, err := ProcessorForRequestHeader(header)
|
|
||||||
|
|
||||||
if scenario.err != err {
|
|
||||||
if scenario.err != nil && err != nil {
|
|
||||||
if scenario.err.Error() != err.Error() {
|
|
||||||
t.Errorf("%d. expected %s, got %s", i, scenario.err, err)
|
|
||||||
}
|
|
||||||
} else if scenario.err != nil || err != nil {
|
|
||||||
t.Errorf("%d. expected %s, got %s", i, scenario.err, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if scenario.output != actual {
|
|
||||||
t.Errorf("%d. expected %s, got %s", i, scenario.output, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDiscriminatorHTTPHeader(t *testing.T) {
|
|
||||||
testDiscriminatorHTTPHeader(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkDiscriminatorHTTPHeader(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
testDiscriminatorHTTPHeader(b)
|
|
||||||
}
|
|
||||||
}
|
|
15
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/extraction.go
generated
vendored
15
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/extraction.go
generated
vendored
@@ -1,15 +0,0 @@
|
|||||||
// 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 extraction decodes Prometheus clients' data streams for consumers.
|
|
||||||
package extraction
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,79 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"baseLabels": {
|
|
||||||
"__name__": "rpc_calls_total",
|
|
||||||
"job": "batch_job"
|
|
||||||
},
|
|
||||||
"docstring": "RPC calls.",
|
|
||||||
"metric": {
|
|
||||||
"type": "counter",
|
|
||||||
"value": [
|
|
||||||
{
|
|
||||||
"labels": {
|
|
||||||
"service": "zed"
|
|
||||||
},
|
|
||||||
"value": 25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"labels": {
|
|
||||||
"service": "bar"
|
|
||||||
},
|
|
||||||
"value": 25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"labels": {
|
|
||||||
"service": "foo"
|
|
||||||
},
|
|
||||||
"value": 25
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"baseLabels": {
|
|
||||||
"__name__": "rpc_latency_microseconds"
|
|
||||||
},
|
|
||||||
"docstring": "RPC latency.",
|
|
||||||
"metric": {
|
|
||||||
"type": "histogram",
|
|
||||||
"value": [
|
|
||||||
{
|
|
||||||
"labels": {
|
|
||||||
"service": "foo"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"0.010000": 15.890724674774395,
|
|
||||||
"0.050000": 15.890724674774395,
|
|
||||||
"0.500000": 84.63044031436561,
|
|
||||||
"0.900000": 160.21100853053224,
|
|
||||||
"0.990000": 172.49828748957728
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"labels": {
|
|
||||||
"service": "zed"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"0.010000": 0.0459814091918713,
|
|
||||||
"0.050000": 0.0459814091918713,
|
|
||||||
"0.500000": 0.6120456642749681,
|
|
||||||
"0.900000": 1.355915069887731,
|
|
||||||
"0.990000": 1.772733213161236
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"labels": {
|
|
||||||
"service": "bar"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"0.010000": 78.48563317257356,
|
|
||||||
"0.050000": 78.48563317257356,
|
|
||||||
"0.500000": 97.31798360385088,
|
|
||||||
"0.900000": 109.89202084295582,
|
|
||||||
"0.990000": 109.99626121011262
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
@@ -1,318 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
|
||||||
|
|
||||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
type metricFamilyProcessor struct{}
|
|
||||||
|
|
||||||
// MetricFamilyProcessor decodes varint encoded record length-delimited streams
|
|
||||||
// of io.prometheus.client.MetricFamily.
|
|
||||||
//
|
|
||||||
// See http://godoc.org/github.com/matttproud/golang_protobuf_extensions/ext for
|
|
||||||
// more details.
|
|
||||||
var MetricFamilyProcessor = &metricFamilyProcessor{}
|
|
||||||
|
|
||||||
func (m *metricFamilyProcessor) ProcessSingle(i io.Reader, out Ingester, o *ProcessOptions) error {
|
|
||||||
family := &dto.MetricFamily{}
|
|
||||||
|
|
||||||
for {
|
|
||||||
family.Reset()
|
|
||||||
|
|
||||||
if _, err := pbutil.ReadDelimited(i, family); err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := extractMetricFamily(out, o, family); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractMetricFamily(out Ingester, o *ProcessOptions, family *dto.MetricFamily) error {
|
|
||||||
switch family.GetType() {
|
|
||||||
case dto.MetricType_COUNTER:
|
|
||||||
if err := extractCounter(out, o, family); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case dto.MetricType_GAUGE:
|
|
||||||
if err := extractGauge(out, o, family); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case dto.MetricType_SUMMARY:
|
|
||||||
if err := extractSummary(out, o, family); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case dto.MetricType_UNTYPED:
|
|
||||||
if err := extractUntyped(out, o, family); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case dto.MetricType_HISTOGRAM:
|
|
||||||
if err := extractHistogram(out, o, family); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractCounter(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error {
|
|
||||||
samples := make(model.Samples, 0, len(f.Metric))
|
|
||||||
|
|
||||||
for _, m := range f.Metric {
|
|
||||||
if m.Counter == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
sample := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(m.Counter.GetValue()),
|
|
||||||
}
|
|
||||||
samples = append(samples, sample)
|
|
||||||
|
|
||||||
if m.TimestampMs != nil {
|
|
||||||
sample.Timestamp = model.TimestampFromUnixNano(*m.TimestampMs * 1000000)
|
|
||||||
} else {
|
|
||||||
sample.Timestamp = o.Timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
metric := sample.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.Ingest(samples)
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractGauge(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error {
|
|
||||||
samples := make(model.Samples, 0, len(f.Metric))
|
|
||||||
|
|
||||||
for _, m := range f.Metric {
|
|
||||||
if m.Gauge == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
sample := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(m.Gauge.GetValue()),
|
|
||||||
}
|
|
||||||
samples = append(samples, sample)
|
|
||||||
|
|
||||||
if m.TimestampMs != nil {
|
|
||||||
sample.Timestamp = model.TimestampFromUnixNano(*m.TimestampMs * 1000000)
|
|
||||||
} else {
|
|
||||||
sample.Timestamp = o.Timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
metric := sample.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.Ingest(samples)
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractSummary(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error {
|
|
||||||
samples := make(model.Samples, 0, len(f.Metric))
|
|
||||||
|
|
||||||
for _, m := range f.Metric {
|
|
||||||
if m.Summary == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
timestamp := o.Timestamp
|
|
||||||
if m.TimestampMs != nil {
|
|
||||||
timestamp = model.TimestampFromUnixNano(*m.TimestampMs * 1000000)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, q := range m.Summary.Quantile {
|
|
||||||
sample := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(q.GetValue()),
|
|
||||||
Timestamp: timestamp,
|
|
||||||
}
|
|
||||||
samples = append(samples, sample)
|
|
||||||
|
|
||||||
metric := sample.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
// BUG(matt): Update other names to "quantile".
|
|
||||||
metric[model.LabelName(model.QuantileLabel)] = model.LabelValue(fmt.Sprint(q.GetQuantile()))
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Summary.SampleSum != nil {
|
|
||||||
sum := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(m.Summary.GetSampleSum()),
|
|
||||||
Timestamp: timestamp,
|
|
||||||
}
|
|
||||||
samples = append(samples, sum)
|
|
||||||
|
|
||||||
metric := sum.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Summary.SampleCount != nil {
|
|
||||||
count := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(m.Summary.GetSampleCount()),
|
|
||||||
Timestamp: timestamp,
|
|
||||||
}
|
|
||||||
samples = append(samples, count)
|
|
||||||
|
|
||||||
metric := count.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.Ingest(samples)
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractUntyped(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error {
|
|
||||||
samples := make(model.Samples, 0, len(f.Metric))
|
|
||||||
|
|
||||||
for _, m := range f.Metric {
|
|
||||||
if m.Untyped == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
sample := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(m.Untyped.GetValue()),
|
|
||||||
}
|
|
||||||
samples = append(samples, sample)
|
|
||||||
|
|
||||||
if m.TimestampMs != nil {
|
|
||||||
sample.Timestamp = model.TimestampFromUnixNano(*m.TimestampMs * 1000000)
|
|
||||||
} else {
|
|
||||||
sample.Timestamp = o.Timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
metric := sample.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.Ingest(samples)
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractHistogram(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error {
|
|
||||||
samples := make(model.Samples, 0, len(f.Metric))
|
|
||||||
|
|
||||||
for _, m := range f.Metric {
|
|
||||||
if m.Histogram == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
timestamp := o.Timestamp
|
|
||||||
if m.TimestampMs != nil {
|
|
||||||
timestamp = model.TimestampFromUnixNano(*m.TimestampMs * 1000000)
|
|
||||||
}
|
|
||||||
|
|
||||||
infSeen := false
|
|
||||||
|
|
||||||
for _, q := range m.Histogram.Bucket {
|
|
||||||
sample := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(q.GetCumulativeCount()),
|
|
||||||
Timestamp: timestamp,
|
|
||||||
}
|
|
||||||
samples = append(samples, sample)
|
|
||||||
|
|
||||||
metric := sample.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.LabelName(model.BucketLabel)] = model.LabelValue(fmt.Sprint(q.GetUpperBound()))
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
|
|
||||||
|
|
||||||
if math.IsInf(q.GetUpperBound(), +1) {
|
|
||||||
infSeen = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Histogram.SampleSum != nil {
|
|
||||||
sum := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(m.Histogram.GetSampleSum()),
|
|
||||||
Timestamp: timestamp,
|
|
||||||
}
|
|
||||||
samples = append(samples, sum)
|
|
||||||
|
|
||||||
metric := sum.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Histogram.SampleCount != nil {
|
|
||||||
count := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: model.SampleValue(m.Histogram.GetSampleCount()),
|
|
||||||
Timestamp: timestamp,
|
|
||||||
}
|
|
||||||
samples = append(samples, count)
|
|
||||||
|
|
||||||
metric := count.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
|
|
||||||
|
|
||||||
if !infSeen {
|
|
||||||
infBucket := &model.Sample{
|
|
||||||
Metric: model.Metric{},
|
|
||||||
Value: count.Value,
|
|
||||||
Timestamp: timestamp,
|
|
||||||
}
|
|
||||||
samples = append(samples, infBucket)
|
|
||||||
|
|
||||||
metric := infBucket.Metric
|
|
||||||
for _, p := range m.Label {
|
|
||||||
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
|
||||||
}
|
|
||||||
metric[model.LabelName(model.BucketLabel)] = model.LabelValue("+Inf")
|
|
||||||
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.Ingest(samples)
|
|
||||||
}
|
|
@@ -1,153 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
var testTime = model.Now()
|
|
||||||
|
|
||||||
type metricFamilyProcessorScenario struct {
|
|
||||||
in string
|
|
||||||
expected, actual []model.Samples
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *metricFamilyProcessorScenario) Ingest(samples model.Samples) error {
|
|
||||||
s.actual = append(s.actual, samples)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *metricFamilyProcessorScenario) test(t *testing.T, set int) {
|
|
||||||
i := strings.NewReader(s.in)
|
|
||||||
|
|
||||||
o := &ProcessOptions{
|
|
||||||
Timestamp: testTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := MetricFamilyProcessor.ProcessSingle(i, s, o)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d. got error: %s", set, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.expected) != len(s.actual) {
|
|
||||||
t.Fatalf("%d. expected length %d, got %d", set, len(s.expected), len(s.actual))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, expected := range s.expected {
|
|
||||||
sort.Sort(s.actual[i])
|
|
||||||
sort.Sort(expected)
|
|
||||||
|
|
||||||
if !expected.Equal(s.actual[i]) {
|
|
||||||
t.Errorf("%d.%d. expected %s, got %s", set, i, expected, s.actual[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMetricFamilyProcessor(t *testing.T) {
|
|
||||||
scenarios := []metricFamilyProcessorScenario{
|
|
||||||
{
|
|
||||||
in: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_label_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@",
|
|
||||||
expected: []model.Samples{
|
|
||||||
model.Samples{
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_count", "some_label_name": "some_label_value"},
|
|
||||||
Value: -42,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_count", "another_label_name": "another_label_value"},
|
|
||||||
Value: 84,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: "\xb9\x01\n\rrequest_count\x12\x12Number of requests\x18\x02\"O\n#\n\x0fsome_label_name\x12\x10some_label_value\"(\x1a\x12\t\xaeG\xe1z\x14\xae\xef?\x11\x00\x00\x00\x00\x00\x00E\xc0\x1a\x12\t+\x87\x16\xd9\xce\xf7\xef?\x11\x00\x00\x00\x00\x00\x00U\xc0\"A\n)\n\x12another_label_name\x12\x13another_label_value\"\x14\x1a\x12\t\x00\x00\x00\x00\x00\x00\xe0?\x11\x00\x00\x00\x00\x00\x00$@",
|
|
||||||
expected: []model.Samples{
|
|
||||||
model.Samples{
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_count", "some_label_name": "some_label_value", "quantile": "0.99"},
|
|
||||||
Value: -42,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_count", "some_label_name": "some_label_value", "quantile": "0.999"},
|
|
||||||
Value: -84,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_count", "another_label_name": "another_label_value", "quantile": "0.5"},
|
|
||||||
Value: 10,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: "\x8d\x01\n\x1drequest_duration_microseconds\x12\x15The response latency.\x18\x04\"S:Q\b\x85\x15\x11\xcd\xcc\xccL\x8f\xcb:A\x1a\v\b{\x11\x00\x00\x00\x00\x00\x00Y@\x1a\f\b\x9c\x03\x11\x00\x00\x00\x00\x00\x00^@\x1a\f\b\xd0\x04\x11\x00\x00\x00\x00\x00\x00b@\x1a\f\b\xf4\v\x11\x9a\x99\x99\x99\x99\x99e@\x1a\f\b\x85\x15\x11\x00\x00\x00\x00\x00\x00\xf0\u007f",
|
|
||||||
expected: []model.Samples{
|
|
||||||
model.Samples{
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_duration_microseconds_bucket", "le": "100"},
|
|
||||||
Value: 123,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_duration_microseconds_bucket", "le": "120"},
|
|
||||||
Value: 412,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_duration_microseconds_bucket", "le": "144"},
|
|
||||||
Value: 592,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_duration_microseconds_bucket", "le": "172.8"},
|
|
||||||
Value: 1524,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_duration_microseconds_bucket", "le": "+Inf"},
|
|
||||||
Value: 2693,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_duration_microseconds_sum"},
|
|
||||||
Value: 1756047.3,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "request_duration_microseconds_count"},
|
|
||||||
Value: 2693,
|
|
||||||
Timestamp: testTime,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
|
||||||
scenario.test(t, i)
|
|
||||||
}
|
|
||||||
}
|
|
84
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor.go
generated
vendored
84
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor.go
generated
vendored
@@ -1,84 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProcessOptions dictates how the interpreted stream should be rendered for
|
|
||||||
// consumption.
|
|
||||||
type ProcessOptions struct {
|
|
||||||
// Timestamp is added to each value from the stream that has no explicit
|
|
||||||
// timestamp set.
|
|
||||||
Timestamp model.Timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ingester consumes result streams in whatever way is desired by the user.
|
|
||||||
type Ingester interface {
|
|
||||||
Ingest(model.Samples) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processor is responsible for decoding the actual message responses from
|
|
||||||
// stream into a format that can be consumed with the end result written
|
|
||||||
// to the results channel.
|
|
||||||
type Processor interface {
|
|
||||||
// ProcessSingle treats the input as a single self-contained message body and
|
|
||||||
// transforms it accordingly. It has no support for streaming.
|
|
||||||
ProcessSingle(in io.Reader, out Ingester, o *ProcessOptions) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to convert map[string]string into LabelSet.
|
|
||||||
//
|
|
||||||
// NOTE: This should be deleted when support for go 1.0.3 is removed; 1.1 is
|
|
||||||
// smart enough to unmarshal JSON objects into LabelSet directly.
|
|
||||||
func labelSet(labels map[string]string) model.LabelSet {
|
|
||||||
labelset := make(model.LabelSet, len(labels))
|
|
||||||
|
|
||||||
for k, v := range labels {
|
|
||||||
labelset[model.LabelName(k)] = model.LabelValue(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return labelset
|
|
||||||
}
|
|
||||||
|
|
||||||
// A basic interface only useful in testing contexts for dispensing the time
|
|
||||||
// in a controlled manner.
|
|
||||||
type instantProvider interface {
|
|
||||||
// The current instant.
|
|
||||||
Now() time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clock is a simple means for fluently wrapping around standard Go timekeeping
|
|
||||||
// mechanisms to enhance testability without compromising code readability.
|
|
||||||
//
|
|
||||||
// It is sufficient for use on bare initialization. A provider should be
|
|
||||||
// set only for test contexts. When not provided, it emits the current
|
|
||||||
// system time.
|
|
||||||
type clock struct {
|
|
||||||
// The underlying means through which time is provided, if supplied.
|
|
||||||
Provider instantProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit the current instant.
|
|
||||||
func (t *clock) Now() time.Time {
|
|
||||||
if t.Provider == nil {
|
|
||||||
return time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
return t.Provider.Now()
|
|
||||||
}
|
|
127
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor0_0_1.go
generated
vendored
127
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor0_0_1.go
generated
vendored
@@ -1,127 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
baseLabels001 = "baseLabels"
|
|
||||||
counter001 = "counter"
|
|
||||||
docstring001 = "docstring"
|
|
||||||
gauge001 = "gauge"
|
|
||||||
histogram001 = "histogram"
|
|
||||||
labels001 = "labels"
|
|
||||||
metric001 = "metric"
|
|
||||||
type001 = "type"
|
|
||||||
value001 = "value"
|
|
||||||
percentile001 = "percentile"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Processor001 is responsible for decoding payloads from protocol version
|
|
||||||
// 0.0.1.
|
|
||||||
var Processor001 = &processor001{}
|
|
||||||
|
|
||||||
// processor001 is responsible for handling API version 0.0.1.
|
|
||||||
type processor001 struct{}
|
|
||||||
|
|
||||||
// entity001 represents a the JSON structure that 0.0.1 uses.
|
|
||||||
type entity001 []struct {
|
|
||||||
BaseLabels map[string]string `json:"baseLabels"`
|
|
||||||
Docstring string `json:"docstring"`
|
|
||||||
Metric struct {
|
|
||||||
MetricType string `json:"type"`
|
|
||||||
Value []struct {
|
|
||||||
Labels map[string]string `json:"labels"`
|
|
||||||
Value interface{} `json:"value"`
|
|
||||||
} `json:"value"`
|
|
||||||
} `json:"metric"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *processor001) ProcessSingle(in io.Reader, out Ingester, o *ProcessOptions) error {
|
|
||||||
// TODO(matt): Replace with plain-jane JSON unmarshalling.
|
|
||||||
buffer, err := ioutil.ReadAll(in)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
entities := entity001{}
|
|
||||||
if err = json.Unmarshal(buffer, &entities); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(matt): This outer loop is a great basis for parallelization.
|
|
||||||
pendingSamples := model.Samples{}
|
|
||||||
for _, entity := range entities {
|
|
||||||
for _, value := range entity.Metric.Value {
|
|
||||||
labels := labelSet(entity.BaseLabels).Merge(labelSet(value.Labels))
|
|
||||||
|
|
||||||
switch entity.Metric.MetricType {
|
|
||||||
case gauge001, counter001:
|
|
||||||
sampleValue, ok := value.Value.(float64)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("could not convert value from %s %s to float64", entity, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingSamples = append(pendingSamples, &model.Sample{
|
|
||||||
Metric: model.Metric(labels),
|
|
||||||
Timestamp: o.Timestamp,
|
|
||||||
Value: model.SampleValue(sampleValue),
|
|
||||||
})
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
case histogram001:
|
|
||||||
sampleValue, ok := value.Value.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("could not convert value from %q to a map[string]interface{}", value.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
for percentile, percentileValue := range sampleValue {
|
|
||||||
individualValue, ok := percentileValue.(float64)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("could not convert value from %q to a float64", percentileValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
childMetric := make(map[model.LabelName]model.LabelValue, len(labels)+1)
|
|
||||||
|
|
||||||
for k, v := range labels {
|
|
||||||
childMetric[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
childMetric[model.LabelName(percentile001)] = model.LabelValue(percentile)
|
|
||||||
|
|
||||||
pendingSamples = append(pendingSamples, &model.Sample{
|
|
||||||
Metric: model.Metric(childMetric),
|
|
||||||
Timestamp: o.Timestamp,
|
|
||||||
Value: model.SampleValue(individualValue),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(pendingSamples) > 0 {
|
|
||||||
return out.Ingest(pendingSamples)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
185
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor0_0_1_test.go
generated
vendored
185
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor0_0_1_test.go
generated
vendored
@@ -1,185 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
var test001Time = model.Now()
|
|
||||||
|
|
||||||
type testProcessor001ProcessScenario struct {
|
|
||||||
in string
|
|
||||||
expected, actual []model.Samples
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testProcessor001ProcessScenario) Ingest(samples model.Samples) error {
|
|
||||||
s.actual = append(s.actual, samples)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testProcessor001ProcessScenario) test(t testing.TB, set int) {
|
|
||||||
reader, err := os.Open(path.Join("fixtures", s.in))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d. couldn't open scenario input file %s: %s", set, s.in, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
options := &ProcessOptions{
|
|
||||||
Timestamp: test001Time,
|
|
||||||
}
|
|
||||||
err = Processor001.ProcessSingle(reader, s, options)
|
|
||||||
if s.err != err && (s.err == nil || err == nil || err.Error() != s.err.Error()) {
|
|
||||||
t.Fatalf("%d. expected err of %s, got %s", set, s.err, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.actual) != len(s.expected) {
|
|
||||||
t.Fatalf("%d. expected output length of %d, got %d", set, len(s.expected), len(s.actual))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, expected := range s.expected {
|
|
||||||
sort.Sort(s.actual[i])
|
|
||||||
sort.Sort(expected)
|
|
||||||
|
|
||||||
if !expected.Equal(s.actual[i]) {
|
|
||||||
t.Errorf("%d.%d. expected %s, got %s", set, i, expected, s.actual[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testProcessor001Process(t testing.TB) {
|
|
||||||
var scenarios = []testProcessor001ProcessScenario{
|
|
||||||
{
|
|
||||||
in: "empty.json",
|
|
||||||
err: errors.New("unexpected end of JSON input"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: "test0_0_1-0_0_2.json",
|
|
||||||
expected: []model.Samples{
|
|
||||||
model.Samples{
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"service": "zed", model.MetricNameLabel: "rpc_calls_total", "job": "batch_job"},
|
|
||||||
Value: 25,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"service": "bar", model.MetricNameLabel: "rpc_calls_total", "job": "batch_job"},
|
|
||||||
Value: 25,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"service": "foo", model.MetricNameLabel: "rpc_calls_total", "job": "batch_job"},
|
|
||||||
Value: 25,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.010000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 0.0459814091918713,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.010000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 78.48563317257356,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.010000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 15.890724674774395,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.050000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 0.0459814091918713,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.050000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 78.48563317257356,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.050000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 15.890724674774395,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.500000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 0.6120456642749681,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.500000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 97.31798360385088,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.500000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 84.63044031436561,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.900000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 1.355915069887731,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.900000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 109.89202084295582,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.900000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 160.21100853053224,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.990000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 1.772733213161236,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.990000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 109.99626121011262,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.990000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 172.49828748957728,
|
|
||||||
Timestamp: test001Time,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
|
||||||
scenario.test(t, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProcessor001Process(t *testing.T) {
|
|
||||||
testProcessor001Process(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkProcessor001Process(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
testProcessor001Process(b)
|
|
||||||
}
|
|
||||||
}
|
|
106
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor0_0_2.go
generated
vendored
106
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor0_0_2.go
generated
vendored
@@ -1,106 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Processor002 is responsible for decoding payloads from protocol version
|
|
||||||
// 0.0.2.
|
|
||||||
var Processor002 = &processor002{}
|
|
||||||
|
|
||||||
type histogram002 struct {
|
|
||||||
Labels map[string]string `json:"labels"`
|
|
||||||
Values map[string]model.SampleValue `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type counter002 struct {
|
|
||||||
Labels map[string]string `json:"labels"`
|
|
||||||
Value model.SampleValue `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type processor002 struct{}
|
|
||||||
|
|
||||||
func (p *processor002) ProcessSingle(in io.Reader, out Ingester, o *ProcessOptions) error {
|
|
||||||
// Processor for telemetry schema version 0.0.2.
|
|
||||||
// container for telemetry data
|
|
||||||
var entities []struct {
|
|
||||||
BaseLabels map[string]string `json:"baseLabels"`
|
|
||||||
Docstring string `json:"docstring"`
|
|
||||||
Metric struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Values json.RawMessage `json:"value"`
|
|
||||||
} `json:"metric"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.NewDecoder(in).Decode(&entities); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingSamples := model.Samples{}
|
|
||||||
for _, entity := range entities {
|
|
||||||
switch entity.Metric.Type {
|
|
||||||
case "counter", "gauge":
|
|
||||||
var values []counter002
|
|
||||||
|
|
||||||
if err := json.Unmarshal(entity.Metric.Values, &values); err != nil {
|
|
||||||
return fmt.Errorf("could not extract %s value: %s", entity.Metric.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, counter := range values {
|
|
||||||
labels := labelSet(entity.BaseLabels).Merge(labelSet(counter.Labels))
|
|
||||||
|
|
||||||
pendingSamples = append(pendingSamples, &model.Sample{
|
|
||||||
Metric: model.Metric(labels),
|
|
||||||
Timestamp: o.Timestamp,
|
|
||||||
Value: counter.Value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
case "histogram":
|
|
||||||
var values []histogram002
|
|
||||||
|
|
||||||
if err := json.Unmarshal(entity.Metric.Values, &values); err != nil {
|
|
||||||
return fmt.Errorf("could not extract %s value: %s", entity.Metric.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, histogram := range values {
|
|
||||||
for percentile, value := range histogram.Values {
|
|
||||||
labels := labelSet(entity.BaseLabels).Merge(labelSet(histogram.Labels))
|
|
||||||
labels[model.LabelName("percentile")] = model.LabelValue(percentile)
|
|
||||||
|
|
||||||
pendingSamples = append(pendingSamples, &model.Sample{
|
|
||||||
Metric: model.Metric(labels),
|
|
||||||
Timestamp: o.Timestamp,
|
|
||||||
Value: value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown metric type %q", entity.Metric.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pendingSamples) > 0 {
|
|
||||||
return out.Ingest(pendingSamples)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
225
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor0_0_2_test.go
generated
vendored
225
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/processor0_0_2_test.go
generated
vendored
@@ -1,225 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
var test002Time = model.Now()
|
|
||||||
|
|
||||||
type testProcessor002ProcessScenario struct {
|
|
||||||
in string
|
|
||||||
expected, actual []model.Samples
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testProcessor002ProcessScenario) Ingest(samples model.Samples) error {
|
|
||||||
s.actual = append(s.actual, samples)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testProcessor002ProcessScenario) test(t testing.TB, set int) {
|
|
||||||
reader, err := os.Open(path.Join("fixtures", s.in))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d. couldn't open scenario input file %s: %s", set, s.in, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
options := &ProcessOptions{
|
|
||||||
Timestamp: test002Time,
|
|
||||||
}
|
|
||||||
err = Processor002.ProcessSingle(reader, s, options)
|
|
||||||
if s.err != err && (s.err == nil || err == nil || err.Error() != s.err.Error()) {
|
|
||||||
t.Fatalf("%d. expected err of %s, got %s", set, s.err, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.actual) != len(s.expected) {
|
|
||||||
t.Fatalf("%d. expected output length of %d, got %d", set, len(s.expected), len(s.actual))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, expected := range s.expected {
|
|
||||||
sort.Sort(s.actual[i])
|
|
||||||
sort.Sort(expected)
|
|
||||||
|
|
||||||
if !expected.Equal(s.actual[i]) {
|
|
||||||
t.Fatalf("%d.%d. expected %s, got %s", set, i, expected, s.actual[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testProcessor002Process(t testing.TB) {
|
|
||||||
var scenarios = []testProcessor002ProcessScenario{
|
|
||||||
{
|
|
||||||
in: "empty.json",
|
|
||||||
err: errors.New("EOF"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
in: "test0_0_1-0_0_2.json",
|
|
||||||
expected: []model.Samples{
|
|
||||||
model.Samples{
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"service": "zed", model.MetricNameLabel: "rpc_calls_total", "job": "batch_job"},
|
|
||||||
Value: 25,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"service": "bar", model.MetricNameLabel: "rpc_calls_total", "job": "batch_job"},
|
|
||||||
Value: 25,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"service": "foo", model.MetricNameLabel: "rpc_calls_total", "job": "batch_job"},
|
|
||||||
Value: 25,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.010000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 0.0459814091918713,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.010000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 78.48563317257356,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.010000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 15.890724674774395,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
|
|
||||||
Metric: model.Metric{"percentile": "0.050000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 0.0459814091918713,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.050000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 78.48563317257356,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.050000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 15.890724674774395,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.500000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 0.6120456642749681,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.500000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 97.31798360385088,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.500000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 84.63044031436561,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.900000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 1.355915069887731,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.900000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 109.89202084295582,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.900000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 160.21100853053224,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.990000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "zed"},
|
|
||||||
Value: 1.772733213161236,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.990000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "bar"},
|
|
||||||
Value: 109.99626121011262,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{"percentile": "0.990000", model.MetricNameLabel: "rpc_latency_microseconds", "service": "foo"},
|
|
||||||
Value: 172.49828748957728,
|
|
||||||
Timestamp: test002Time,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
|
||||||
scenario.test(t, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProcessor002Process(t *testing.T) {
|
|
||||||
testProcessor002Process(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkProcessor002Process(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
|
|
||||||
pre := runtime.MemStats{}
|
|
||||||
runtime.ReadMemStats(&pre)
|
|
||||||
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
testProcessor002Process(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
post := runtime.MemStats{}
|
|
||||||
runtime.ReadMemStats(&post)
|
|
||||||
|
|
||||||
allocated := post.TotalAlloc - pre.TotalAlloc
|
|
||||||
|
|
||||||
b.Logf("Allocated %d at %f per cycle with %d cycles.", allocated, float64(allocated)/float64(b.N), b.N)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkProcessor002ParseOnly(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
data, err := ioutil.ReadFile("fixtures/test0_0_1-0_0_2-large.json")
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
ing := fakeIngester{}
|
|
||||||
b.StartTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
if err := Processor002.ProcessSingle(bytes.NewReader(data), ing, &ProcessOptions{}); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type fakeIngester struct{}
|
|
||||||
|
|
||||||
func (i fakeIngester) Ingest(model.Samples) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
40
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/textprocessor.go
generated
vendored
40
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/textprocessor.go
generated
vendored
@@ -1,40 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/text"
|
|
||||||
)
|
|
||||||
|
|
||||||
type processor004 struct{}
|
|
||||||
|
|
||||||
// Processor004 s responsible for decoding payloads from the text based variety
|
|
||||||
// of protocol version 0.0.4.
|
|
||||||
var Processor004 = &processor004{}
|
|
||||||
|
|
||||||
func (t *processor004) ProcessSingle(i io.Reader, out Ingester, o *ProcessOptions) error {
|
|
||||||
var parser text.Parser
|
|
||||||
metricFamilies, err := parser.TextToMetricFamilies(i)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, metricFamily := range metricFamilies {
|
|
||||||
if err := extractMetricFamily(out, o, metricFamily); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
100
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/textprocessor_test.go
generated
vendored
100
Godeps/_workspace/src/github.com/prometheus/client_golang/extraction/textprocessor_test.go
generated
vendored
@@ -1,100 +0,0 @@
|
|||||||
// 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 extraction
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ts = model.Now()
|
|
||||||
in = `
|
|
||||||
# Only a quite simple scenario with two metric families.
|
|
||||||
# More complicated tests of the parser itself can be found in the text package.
|
|
||||||
# TYPE mf2 counter
|
|
||||||
mf2 3
|
|
||||||
mf1{label="value1"} -3.14 123456
|
|
||||||
mf1{label="value2"} 42
|
|
||||||
mf2 4
|
|
||||||
`
|
|
||||||
out = map[model.LabelValue]model.Samples{
|
|
||||||
"mf1": model.Samples{
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "mf1", "label": "value1"},
|
|
||||||
Value: -3.14,
|
|
||||||
Timestamp: 123456,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "mf1", "label": "value2"},
|
|
||||||
Value: 42,
|
|
||||||
Timestamp: ts,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"mf2": model.Samples{
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "mf2"},
|
|
||||||
Value: 3,
|
|
||||||
Timestamp: ts,
|
|
||||||
},
|
|
||||||
&model.Sample{
|
|
||||||
Metric: model.Metric{model.MetricNameLabel: "mf2"},
|
|
||||||
Value: 4,
|
|
||||||
Timestamp: ts,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type testIngester struct {
|
|
||||||
results []model.Samples
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *testIngester) Ingest(s model.Samples) error {
|
|
||||||
i.results = append(i.results, s)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTextProcessor(t *testing.T) {
|
|
||||||
var ingester testIngester
|
|
||||||
i := strings.NewReader(in)
|
|
||||||
o := &ProcessOptions{
|
|
||||||
Timestamp: ts,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := Processor004.ProcessSingle(i, &ingester, o)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if expected, got := len(out), len(ingester.results); expected != got {
|
|
||||||
t.Fatalf("Expected length %d, got %d", expected, got)
|
|
||||||
}
|
|
||||||
for _, r := range ingester.results {
|
|
||||||
expected, ok := out[r[0].Metric[model.MetricNameLabel]]
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf(
|
|
||||||
"Unexpected metric name %q",
|
|
||||||
r[0].Metric[model.MetricNameLabel],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
sort.Sort(expected)
|
|
||||||
sort.Sort(r)
|
|
||||||
if !expected.Equal(r) {
|
|
||||||
t.Errorf("expected %s, got %s", expected, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
71
Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go
generated
vendored
71
Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go
generated
vendored
@@ -1,71 +0,0 @@
|
|||||||
// 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 (
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ExporterLabelPrefix is the label name prefix to prepend if a
|
|
||||||
// synthetic label is already present in the exported metrics.
|
|
||||||
ExporterLabelPrefix LabelName = "exporter_"
|
|
||||||
|
|
||||||
// MetricNameLabel is the label name indicating the metric name of a
|
|
||||||
// timeseries.
|
|
||||||
MetricNameLabel LabelName = "__name__"
|
|
||||||
|
|
||||||
// ReservedLabelPrefix is a prefix which is not legal in user-supplied
|
|
||||||
// label names.
|
|
||||||
ReservedLabelPrefix = "__"
|
|
||||||
|
|
||||||
// JobLabel is the label name indicating the job from which a timeseries
|
|
||||||
// was scraped.
|
|
||||||
JobLabel LabelName = "job"
|
|
||||||
|
|
||||||
// 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"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A LabelName is a key for a LabelSet or Metric. It has a value associated
|
|
||||||
// therewith.
|
|
||||||
type LabelName string
|
|
||||||
|
|
||||||
// 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, ", ")
|
|
||||||
}
|
|
55
Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname_test.go
generated
vendored
55
Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname_test.go
generated
vendored
@@ -1,55 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
64
Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelset.go
generated
vendored
64
Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelset.go
generated
vendored
@@ -1,64 +0,0 @@
|
|||||||
// 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"
|
|
||||||
"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
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
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, ", "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeFromMetric merges Metric into this LabelSet.
|
|
||||||
func (l LabelSet) MergeFromMetric(m Metric) {
|
|
||||||
for k, v := range m {
|
|
||||||
l[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
121
Godeps/_workspace/src/github.com/prometheus/client_golang/model/metric_test.go
generated
vendored
121
Godeps/_workspace/src/github.com/prometheus/client_golang/model/metric_test.go
generated
vendored
@@ -1,121 +0,0 @@
|
|||||||
// 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 Metric
|
|
||||||
fingerprint Fingerprint
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
input: Metric{},
|
|
||||||
fingerprint: 14695981039346656037,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: Metric{
|
|
||||||
"first_name": "electro",
|
|
||||||
"occupation": "robot",
|
|
||||||
"manufacturer": "westinghouse",
|
|
||||||
},
|
|
||||||
fingerprint: 11310079640881077873,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: Metric{
|
|
||||||
"x": "y",
|
|
||||||
},
|
|
||||||
fingerprint: 13948396922932177635,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: Metric{
|
|
||||||
"a": "bb",
|
|
||||||
"b": "c",
|
|
||||||
},
|
|
||||||
fingerprint: 3198632812309449502,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: Metric{
|
|
||||||
"a": "b",
|
|
||||||
"bb": "c",
|
|
||||||
},
|
|
||||||
fingerprint: 5774953389407657638,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
|
||||||
if scenario.fingerprint != scenario.input.Fingerprint() {
|
|
||||||
t.Errorf("%d. expected %d, got %d", i, scenario.fingerprint, scenario.input.Fingerprint())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.Delete("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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
79
Godeps/_workspace/src/github.com/prometheus/client_golang/model/sample.go
generated
vendored
79
Godeps/_workspace/src/github.com/prometheus/client_golang/model/sample.go
generated
vendored
@@ -1,79 +0,0 @@
|
|||||||
// 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
|
|
||||||
|
|
||||||
// Sample is a sample value with a timestamp and a metric.
|
|
||||||
type Sample struct {
|
|
||||||
Metric Metric
|
|
||||||
Value SampleValue
|
|
||||||
Timestamp Timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.Equal(o.Value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
126
Godeps/_workspace/src/github.com/prometheus/client_golang/model/sample_test.go
generated
vendored
126
Godeps/_workspace/src/github.com/prometheus/client_golang/model/sample_test.go
generated
vendored
@@ -1,126 +0,0 @@
|
|||||||
// 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 TestSamplesSort(t *testing.T) {
|
|
||||||
input := Samples{
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 81f9c9ed24563f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "A",
|
|
||||||
},
|
|
||||||
Timestamp: 1,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 81f9c9ed24563f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "A",
|
|
||||||
},
|
|
||||||
Timestamp: 2,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 1bf6c9ed24543f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "C",
|
|
||||||
},
|
|
||||||
Timestamp: 1,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 1bf6c9ed24543f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "C",
|
|
||||||
},
|
|
||||||
Timestamp: 2,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 68f4c9ed24533f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "B",
|
|
||||||
},
|
|
||||||
Timestamp: 1,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 68f4c9ed24533f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "B",
|
|
||||||
},
|
|
||||||
Timestamp: 2,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := Samples{
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 1bf6c9ed24543f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "C",
|
|
||||||
},
|
|
||||||
Timestamp: 1,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 1bf6c9ed24543f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "C",
|
|
||||||
},
|
|
||||||
Timestamp: 2,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 68f4c9ed24533f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "B",
|
|
||||||
},
|
|
||||||
Timestamp: 1,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 68f4c9ed24533f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "B",
|
|
||||||
},
|
|
||||||
Timestamp: 2,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 81f9c9ed24563f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "A",
|
|
||||||
},
|
|
||||||
Timestamp: 1,
|
|
||||||
},
|
|
||||||
&Sample{
|
|
||||||
// Fingerprint: 81f9c9ed24563f8f.
|
|
||||||
Metric: Metric{
|
|
||||||
MetricNameLabel: "A",
|
|
||||||
},
|
|
||||||
Timestamp: 2,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Sort(input)
|
|
||||||
|
|
||||||
for i, actual := range input {
|
|
||||||
actualFp := actual.Metric.Fingerprint()
|
|
||||||
expectedFp := expected[i].Metric.Fingerprint()
|
|
||||||
|
|
||||||
if !actualFp.Equal(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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
37
Godeps/_workspace/src/github.com/prometheus/client_golang/model/samplevalue.go
generated
vendored
37
Godeps/_workspace/src/github.com/prometheus/client_golang/model/samplevalue.go
generated
vendored
@@ -1,37 +0,0 @@
|
|||||||
// 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"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A SampleValue is a representation of a value for a given sample at a given
|
|
||||||
// time.
|
|
||||||
type SampleValue float64
|
|
||||||
|
|
||||||
// Equal does a straight v==o.
|
|
||||||
func (v SampleValue) Equal(o SampleValue) bool {
|
|
||||||
return v == o
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON implements json.Marshaler.
|
|
||||||
func (v SampleValue) MarshalJSON() ([]byte, error) {
|
|
||||||
return []byte(fmt.Sprintf(`"%s"`, v)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v SampleValue) String() string {
|
|
||||||
return strconv.FormatFloat(float64(v), 'f', -1, 64)
|
|
||||||
}
|
|
116
Godeps/_workspace/src/github.com/prometheus/client_golang/model/timestamp.go
generated
vendored
116
Godeps/_workspace/src/github.com/prometheus/client_golang/model/timestamp.go
generated
vendored
@@ -1,116 +0,0 @@
|
|||||||
// 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 (
|
|
||||||
"math"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
native_time "time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Timestamp is the number of milliseconds since the epoch
|
|
||||||
// (1970-01-01 00:00 UTC) excluding leap seconds.
|
|
||||||
type Timestamp int64
|
|
||||||
|
|
||||||
const (
|
|
||||||
// MinimumTick is the minimum supported time resolution. This has to be
|
|
||||||
// at least native_time.Second in order for the code below to work.
|
|
||||||
MinimumTick = native_time.Millisecond
|
|
||||||
// second is the timestamp duration equivalent to one second.
|
|
||||||
second = int64(native_time.Second / MinimumTick)
|
|
||||||
// The number of nanoseconds per minimum tick.
|
|
||||||
nanosPerTick = int64(MinimumTick / native_time.Nanosecond)
|
|
||||||
|
|
||||||
// Earliest is the earliest timestamp representable. Handy for
|
|
||||||
// initializing a high watermark.
|
|
||||||
Earliest = Timestamp(math.MinInt64)
|
|
||||||
// Latest is the latest timestamp representable. Handy for initializing
|
|
||||||
// a low watermark.
|
|
||||||
Latest = Timestamp(math.MaxInt64)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Equal reports whether two timestamps represent the same instant.
|
|
||||||
func (t Timestamp) Equal(o Timestamp) bool {
|
|
||||||
return t == o
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before reports whether the timestamp t is before o.
|
|
||||||
func (t Timestamp) Before(o Timestamp) bool {
|
|
||||||
return t < o
|
|
||||||
}
|
|
||||||
|
|
||||||
// After reports whether the timestamp t is after o.
|
|
||||||
func (t Timestamp) After(o Timestamp) bool {
|
|
||||||
return t > o
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add returns the Timestamp t + d.
|
|
||||||
func (t Timestamp) Add(d native_time.Duration) Timestamp {
|
|
||||||
return t + Timestamp(d/MinimumTick)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sub returns the Duration t - o.
|
|
||||||
func (t Timestamp) Sub(o Timestamp) native_time.Duration {
|
|
||||||
return native_time.Duration(t-o) * MinimumTick
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time returns the time.Time representation of t.
|
|
||||||
func (t Timestamp) Time() native_time.Time {
|
|
||||||
return native_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 Timestamp) 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 Timestamp) UnixNano() int64 {
|
|
||||||
return int64(t) * nanosPerTick
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of the timestamp.
|
|
||||||
func (t Timestamp) String() string {
|
|
||||||
return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
|
||||||
func (t Timestamp) MarshalJSON() ([]byte, error) {
|
|
||||||
return []byte(t.String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now returns the current time as a Timestamp.
|
|
||||||
func Now() Timestamp {
|
|
||||||
return TimestampFromTime(native_time.Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimestampFromTime returns the Timestamp equivalent to the time.Time t.
|
|
||||||
func TimestampFromTime(t native_time.Time) Timestamp {
|
|
||||||
return TimestampFromUnixNano(t.UnixNano())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimestampFromUnix returns the Timestamp equivalent to the Unix timestamp t
|
|
||||||
// provided in seconds.
|
|
||||||
func TimestampFromUnix(t int64) Timestamp {
|
|
||||||
return Timestamp(t * second)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimestampFromUnixNano returns the Timestamp equivalent to the Unix timestamp
|
|
||||||
// t provided in nanoseconds.
|
|
||||||
func TimestampFromUnixNano(t int64) Timestamp {
|
|
||||||
return Timestamp(t / nanosPerTick)
|
|
||||||
}
|
|
2
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/counter.go
generated
vendored
2
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/counter.go
generated
vendored
@@ -33,7 +33,7 @@ type Counter interface {
|
|||||||
|
|
||||||
// Set is used to set the Counter to an arbitrary value. It is only used
|
// Set is used to set the Counter to an arbitrary value. It is only used
|
||||||
// if you have to transfer a value from an external counter into this
|
// if you have to transfer a value from an external counter into this
|
||||||
// Prometheus metrics. Do not use it for regular handling of a
|
// Prometheus metric. Do not use it for regular handling of a
|
||||||
// Prometheus counter (as it can be used to break the contract of
|
// Prometheus counter (as it can be used to break the contract of
|
||||||
// monotonically increasing values).
|
// monotonically increasing values).
|
||||||
Set(float64)
|
Set(float64)
|
||||||
|
18
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/desc.go
generated
vendored
18
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/desc.go
generated
vendored
@@ -9,18 +9,20 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
metricNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`)
|
metricNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`)
|
||||||
labelNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
|
labelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// reservedLabelPrefix is a prefix which is not legal in user-supplied
|
||||||
|
// label names.
|
||||||
|
const reservedLabelPrefix = "__"
|
||||||
|
|
||||||
// Labels represents a collection of label name -> value mappings. This type is
|
// Labels represents a collection of label name -> value mappings. This type is
|
||||||
// commonly used with the With(Labels) and GetMetricWith(Labels) methods of
|
// commonly used with the With(Labels) and GetMetricWith(Labels) methods of
|
||||||
// metric vector Collectors, e.g.:
|
// metric vector Collectors, e.g.:
|
||||||
@@ -134,7 +136,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
|
|||||||
for _, val := range labelValues {
|
for _, val := range labelValues {
|
||||||
b.Reset()
|
b.Reset()
|
||||||
b.WriteString(val)
|
b.WriteString(val)
|
||||||
b.WriteByte(model.SeparatorByte)
|
b.WriteByte(separatorByte)
|
||||||
h.Write(b.Bytes())
|
h.Write(b.Bytes())
|
||||||
}
|
}
|
||||||
d.id = h.Sum64()
|
d.id = h.Sum64()
|
||||||
@@ -145,12 +147,12 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
|
|||||||
h.Reset()
|
h.Reset()
|
||||||
b.Reset()
|
b.Reset()
|
||||||
b.WriteString(help)
|
b.WriteString(help)
|
||||||
b.WriteByte(model.SeparatorByte)
|
b.WriteByte(separatorByte)
|
||||||
h.Write(b.Bytes())
|
h.Write(b.Bytes())
|
||||||
for _, labelName := range labelNames {
|
for _, labelName := range labelNames {
|
||||||
b.Reset()
|
b.Reset()
|
||||||
b.WriteString(labelName)
|
b.WriteString(labelName)
|
||||||
b.WriteByte(model.SeparatorByte)
|
b.WriteByte(separatorByte)
|
||||||
h.Write(b.Bytes())
|
h.Write(b.Bytes())
|
||||||
}
|
}
|
||||||
d.dimHash = h.Sum64()
|
d.dimHash = h.Sum64()
|
||||||
@@ -195,5 +197,5 @@ func (d *Desc) String() string {
|
|||||||
|
|
||||||
func checkLabelName(l string) bool {
|
func checkLabelName(l string) bool {
|
||||||
return labelNameRE.MatchString(l) &&
|
return labelNameRE.MatchString(l) &&
|
||||||
!strings.HasPrefix(l, model.ReservedLabelPrefix)
|
!strings.HasPrefix(l, reservedLabelPrefix)
|
||||||
}
|
}
|
||||||
|
11
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/doc.go
generated
vendored
11
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/doc.go
generated
vendored
@@ -61,12 +61,13 @@
|
|||||||
// It also exports some stats about the HTTP usage of the /metrics
|
// It also exports some stats about the HTTP usage of the /metrics
|
||||||
// endpoint. (See the Handler function for more detail.)
|
// endpoint. (See the Handler function for more detail.)
|
||||||
//
|
//
|
||||||
// A more advanced metric type is the Summary.
|
// Two more advanced metric types are the Summary and Histogram.
|
||||||
//
|
//
|
||||||
// In addition to the fundamental metric types Gauge, Counter, and Summary, a
|
// In addition to the fundamental metric types Gauge, Counter, Summary, and
|
||||||
// very important part of the Prometheus data model is the partitioning of
|
// Histogram, a very important part of the Prometheus data model is the
|
||||||
// samples along dimensions called labels, which results in metric vectors. The
|
// partitioning of samples along dimensions called labels, which results in
|
||||||
// fundamental types are GaugeVec, CounterVec, and SummaryVec.
|
// metric vectors. The fundamental types are GaugeVec, CounterVec, SummaryVec,
|
||||||
|
// and HistogramVec.
|
||||||
//
|
//
|
||||||
// Those are all the parts needed for basic usage. Detailed documentation and
|
// Those are all the parts needed for basic usage. Detailed documentation and
|
||||||
// examples are provided below.
|
// examples are provided below.
|
||||||
|
131
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/examples_test.go
generated
vendored
131
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/examples_test.go
generated
vendored
@@ -392,6 +392,9 @@ func ExampleSummaryVec() {
|
|||||||
temps.WithLabelValues("lithobates-catesbeianus").Observe(32 + math.Floor(100*math.Cos(float64(i)*0.11))/10)
|
temps.WithLabelValues("lithobates-catesbeianus").Observe(32 + math.Floor(100*math.Cos(float64(i)*0.11))/10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a Summary without any observations.
|
||||||
|
temps.WithLabelValues("leiopelma-hochstetteri")
|
||||||
|
|
||||||
// Just for demonstration, let's check the state of the summary vector
|
// Just for demonstration, let's check the state of the summary vector
|
||||||
// by (ab)using its Collect method and the Write method of its elements
|
// by (ab)using its Collect method and the Write method of its elements
|
||||||
// (which is usually only used by Prometheus internally - code like the
|
// (which is usually only used by Prometheus internally - code like the
|
||||||
@@ -414,6 +417,26 @@ func ExampleSummaryVec() {
|
|||||||
// Output:
|
// Output:
|
||||||
// [label: <
|
// [label: <
|
||||||
// name: "species"
|
// name: "species"
|
||||||
|
// value: "leiopelma-hochstetteri"
|
||||||
|
// >
|
||||||
|
// summary: <
|
||||||
|
// sample_count: 0
|
||||||
|
// sample_sum: 0
|
||||||
|
// quantile: <
|
||||||
|
// quantile: 0.5
|
||||||
|
// value: nan
|
||||||
|
// >
|
||||||
|
// quantile: <
|
||||||
|
// quantile: 0.9
|
||||||
|
// value: nan
|
||||||
|
// >
|
||||||
|
// quantile: <
|
||||||
|
// quantile: 0.99
|
||||||
|
// value: nan
|
||||||
|
// >
|
||||||
|
// >
|
||||||
|
// label: <
|
||||||
|
// name: "species"
|
||||||
// value: "lithobates-catesbeianus"
|
// value: "lithobates-catesbeianus"
|
||||||
// >
|
// >
|
||||||
// summary: <
|
// summary: <
|
||||||
@@ -455,6 +478,56 @@ func ExampleSummaryVec() {
|
|||||||
// ]
|
// ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleConstSummary() {
|
||||||
|
desc := prometheus.NewDesc(
|
||||||
|
"http_request_duration_seconds",
|
||||||
|
"A summary of the HTTP request durations.",
|
||||||
|
[]string{"code", "method"},
|
||||||
|
prometheus.Labels{"owner": "example"},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a constant summary from values we got from a 3rd party telemetry system.
|
||||||
|
s := prometheus.MustNewConstSummary(
|
||||||
|
desc,
|
||||||
|
4711, 403.34,
|
||||||
|
map[float64]float64{0.5: 42.3, 0.9: 323.3},
|
||||||
|
"200", "get",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Just for demonstration, let's check the state of the summary by
|
||||||
|
// (ab)using its Write method (which is usually only used by Prometheus
|
||||||
|
// internally).
|
||||||
|
metric := &dto.Metric{}
|
||||||
|
s.Write(metric)
|
||||||
|
fmt.Println(proto.MarshalTextString(metric))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// label: <
|
||||||
|
// name: "code"
|
||||||
|
// value: "200"
|
||||||
|
// >
|
||||||
|
// label: <
|
||||||
|
// name: "method"
|
||||||
|
// value: "get"
|
||||||
|
// >
|
||||||
|
// label: <
|
||||||
|
// name: "owner"
|
||||||
|
// value: "example"
|
||||||
|
// >
|
||||||
|
// summary: <
|
||||||
|
// sample_count: 4711
|
||||||
|
// sample_sum: 403.34
|
||||||
|
// quantile: <
|
||||||
|
// quantile: 0.5
|
||||||
|
// value: 42.3
|
||||||
|
// >
|
||||||
|
// quantile: <
|
||||||
|
// quantile: 0.9
|
||||||
|
// value: 323.3
|
||||||
|
// >
|
||||||
|
// >
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleHistogram() {
|
func ExampleHistogram() {
|
||||||
temps := prometheus.NewHistogram(prometheus.HistogramOpts{
|
temps := prometheus.NewHistogram(prometheus.HistogramOpts{
|
||||||
Name: "pond_temperature_celsius",
|
Name: "pond_temperature_celsius",
|
||||||
@@ -501,6 +574,64 @@ func ExampleHistogram() {
|
|||||||
// >
|
// >
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleConstHistogram() {
|
||||||
|
desc := prometheus.NewDesc(
|
||||||
|
"http_request_duration_seconds",
|
||||||
|
"A histogram of the HTTP request durations.",
|
||||||
|
[]string{"code", "method"},
|
||||||
|
prometheus.Labels{"owner": "example"},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a constant histogram from values we got from a 3rd party telemetry system.
|
||||||
|
h := prometheus.MustNewConstHistogram(
|
||||||
|
desc,
|
||||||
|
4711, 403.34,
|
||||||
|
map[float64]uint64{25: 121, 50: 2403, 100: 3221, 200: 4233},
|
||||||
|
"200", "get",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Just for demonstration, let's check the state of the histogram by
|
||||||
|
// (ab)using its Write method (which is usually only used by Prometheus
|
||||||
|
// internally).
|
||||||
|
metric := &dto.Metric{}
|
||||||
|
h.Write(metric)
|
||||||
|
fmt.Println(proto.MarshalTextString(metric))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// label: <
|
||||||
|
// name: "code"
|
||||||
|
// value: "200"
|
||||||
|
// >
|
||||||
|
// label: <
|
||||||
|
// name: "method"
|
||||||
|
// value: "get"
|
||||||
|
// >
|
||||||
|
// label: <
|
||||||
|
// name: "owner"
|
||||||
|
// value: "example"
|
||||||
|
// >
|
||||||
|
// histogram: <
|
||||||
|
// sample_count: 4711
|
||||||
|
// sample_sum: 403.34
|
||||||
|
// bucket: <
|
||||||
|
// cumulative_count: 121
|
||||||
|
// upper_bound: 25
|
||||||
|
// >
|
||||||
|
// bucket: <
|
||||||
|
// cumulative_count: 2403
|
||||||
|
// upper_bound: 50
|
||||||
|
// >
|
||||||
|
// bucket: <
|
||||||
|
// cumulative_count: 3221
|
||||||
|
// upper_bound: 100
|
||||||
|
// >
|
||||||
|
// bucket: <
|
||||||
|
// cumulative_count: 4233
|
||||||
|
// upper_bound: 200
|
||||||
|
// >
|
||||||
|
// >
|
||||||
|
}
|
||||||
|
|
||||||
func ExamplePushCollectors() {
|
func ExamplePushCollectors() {
|
||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
completionTime := prometheus.NewGauge(prometheus.GaugeOpts{
|
completionTime := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
21
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/go_collector.go
generated
vendored
21
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/go_collector.go
generated
vendored
@@ -2,10 +2,13 @@ package prometheus
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type goCollector struct {
|
type goCollector struct {
|
||||||
goroutines Gauge
|
goroutines Gauge
|
||||||
|
gcDesc *Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGoCollector returns a collector which exports metrics about the current
|
// NewGoCollector returns a collector which exports metrics about the current
|
||||||
@@ -13,19 +16,35 @@ type goCollector struct {
|
|||||||
func NewGoCollector() *goCollector {
|
func NewGoCollector() *goCollector {
|
||||||
return &goCollector{
|
return &goCollector{
|
||||||
goroutines: NewGauge(GaugeOpts{
|
goroutines: NewGauge(GaugeOpts{
|
||||||
Name: "process_goroutines",
|
Name: "go_goroutines",
|
||||||
Help: "Number of goroutines that currently exist.",
|
Help: "Number of goroutines that currently exist.",
|
||||||
}),
|
}),
|
||||||
|
gcDesc: NewDesc(
|
||||||
|
"go_gc_duration_seconds",
|
||||||
|
"A summary of the GC invocation durations.",
|
||||||
|
nil, nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe returns all descriptions of the collector.
|
// Describe returns all descriptions of the collector.
|
||||||
func (c *goCollector) Describe(ch chan<- *Desc) {
|
func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||||
ch <- c.goroutines.Desc()
|
ch <- c.goroutines.Desc()
|
||||||
|
ch <- c.gcDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect returns the current state of all metrics of the collector.
|
// Collect returns the current state of all metrics of the collector.
|
||||||
func (c *goCollector) Collect(ch chan<- Metric) {
|
func (c *goCollector) Collect(ch chan<- Metric) {
|
||||||
c.goroutines.Set(float64(runtime.NumGoroutine()))
|
c.goroutines.Set(float64(runtime.NumGoroutine()))
|
||||||
ch <- c.goroutines
|
ch <- c.goroutines
|
||||||
|
|
||||||
|
var stats debug.GCStats
|
||||||
|
stats.PauseQuantiles = make([]time.Duration, 5)
|
||||||
|
debug.ReadGCStats(&stats)
|
||||||
|
|
||||||
|
quantiles := make(map[float64]float64)
|
||||||
|
for idx, pq := range stats.PauseQuantiles[1:] {
|
||||||
|
quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds()
|
||||||
|
}
|
||||||
|
quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
|
||||||
|
ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles)
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -35,6 +35,9 @@ func TestGoCollector(t *testing.T) {
|
|||||||
case Gauge:
|
case Gauge:
|
||||||
pb := &dto.Metric{}
|
pb := &dto.Metric{}
|
||||||
m.Write(pb)
|
m.Write(pb)
|
||||||
|
if pb.GetGauge() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if old == -1 {
|
if old == -1 {
|
||||||
old = int(pb.GetGauge().GetValue())
|
old = int(pb.GetGauge().GetValue())
|
||||||
@@ -47,9 +50,71 @@ func TestGoCollector(t *testing.T) {
|
|||||||
t.Errorf("want 1 new goroutine, got %d", diff)
|
t.Errorf("want 1 new goroutine, got %d", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoCollector performs two sends per call.
|
||||||
|
// On line 27 we need to receive the second send
|
||||||
|
// to shut down cleanly.
|
||||||
|
<-ch
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
t.Fatalf("expected collect timed out")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGCCollector(t *testing.T) {
|
||||||
|
var (
|
||||||
|
c = NewGoCollector()
|
||||||
|
ch = make(chan Metric)
|
||||||
|
waitc = make(chan struct{})
|
||||||
|
closec = make(chan struct{})
|
||||||
|
oldGC uint64
|
||||||
|
oldPause float64
|
||||||
|
)
|
||||||
|
defer close(closec)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
c.Collect(ch)
|
||||||
|
// force GC
|
||||||
|
runtime.GC()
|
||||||
|
<-waitc
|
||||||
|
c.Collect(ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
first := true
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case metric := <-ch:
|
||||||
|
switch m := metric.(type) {
|
||||||
|
case *constSummary, *value:
|
||||||
|
pb := &dto.Metric{}
|
||||||
|
m.Write(pb)
|
||||||
|
if pb.GetSummary() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pb.GetSummary().Quantile) != 5 {
|
||||||
|
t.Errorf("expected 4 buckets, got %d", len(pb.GetSummary().Quantile))
|
||||||
|
}
|
||||||
|
for idx, want := range []float64{0.0, 0.25, 0.5, 0.75, 1.0} {
|
||||||
|
if *pb.GetSummary().Quantile[idx].Quantile != want {
|
||||||
|
t.Errorf("bucket #%d is off, got %f, want %f", idx, *pb.GetSummary().Quantile[idx].Quantile, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
oldGC = *pb.GetSummary().SampleCount
|
||||||
|
oldPause = *pb.GetSummary().SampleSum
|
||||||
|
close(waitc)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if diff := *pb.GetSummary().SampleCount - oldGC; diff != 1 {
|
||||||
|
t.Errorf("want 1 new garbage collection run, got %d", diff)
|
||||||
|
}
|
||||||
|
if diff := *pb.GetSummary().SampleSum - oldPause; diff <= 0 {
|
||||||
|
t.Errorf("want moar pause, got %f", diff)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
default:
|
|
||||||
t.Errorf("want type Gauge, got %s", reflect.TypeOf(metric))
|
|
||||||
}
|
}
|
||||||
case <-time.After(1 * time.Second):
|
case <-time.After(1 * time.Second):
|
||||||
t.Fatalf("expected collect timed out")
|
t.Fatalf("expected collect timed out")
|
||||||
|
122
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/histogram.go
generated
vendored
122
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/histogram.go
generated
vendored
@@ -22,7 +22,6 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,6 +48,10 @@ type Histogram interface {
|
|||||||
Observe(float64)
|
Observe(float64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bucketLabel is used for the label that defines the upper bound of a
|
||||||
|
// bucket of a histogram ("le" -> "less or equal").
|
||||||
|
const bucketLabel = "le"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefBuckets are the default Histogram buckets. The default buckets are
|
// DefBuckets are the default Histogram buckets. The default buckets are
|
||||||
// tailored to broadly measure the response time (in seconds) of a
|
// tailored to broadly measure the response time (in seconds) of a
|
||||||
@@ -57,7 +60,7 @@ var (
|
|||||||
DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
|
DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
|
||||||
|
|
||||||
errBucketLabelNotAllowed = fmt.Errorf(
|
errBucketLabelNotAllowed = fmt.Errorf(
|
||||||
"%q is not allowed as label name in histograms", model.BucketLabel,
|
"%q is not allowed as label name in histograms", bucketLabel,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -147,7 +150,7 @@ type HistogramOpts struct {
|
|||||||
// element in the slice is the upper inclusive bound of a bucket. The
|
// element in the slice is the upper inclusive bound of a bucket. The
|
||||||
// values must be sorted in strictly increasing order. There is no need
|
// values must be sorted in strictly increasing order. There is no need
|
||||||
// to add a highest bucket with +Inf bound, it will be added
|
// to add a highest bucket with +Inf bound, it will be added
|
||||||
// implicitly. The default value is DefObjectives.
|
// implicitly. The default value is DefBuckets.
|
||||||
Buckets []float64
|
Buckets []float64
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,12 +174,12 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, n := range desc.variableLabels {
|
for _, n := range desc.variableLabels {
|
||||||
if n == model.BucketLabel {
|
if n == bucketLabel {
|
||||||
panic(errBucketLabelNotAllowed)
|
panic(errBucketLabelNotAllowed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, lp := range desc.constLabelPairs {
|
for _, lp := range desc.constLabelPairs {
|
||||||
if lp.GetName() == model.BucketLabel {
|
if lp.GetName() == bucketLabel {
|
||||||
panic(errBucketLabelNotAllowed)
|
panic(errBucketLabelNotAllowed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,6 +216,13 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
|||||||
}
|
}
|
||||||
|
|
||||||
type histogram struct {
|
type histogram struct {
|
||||||
|
// sumBits contains the bits of the float64 representing the sum of all
|
||||||
|
// observations. sumBits and count have to go first in the struct to
|
||||||
|
// guarantee alignment for atomic operations.
|
||||||
|
// http://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||||
|
sumBits uint64
|
||||||
|
count uint64
|
||||||
|
|
||||||
SelfCollector
|
SelfCollector
|
||||||
// Note that there is no mutex required.
|
// Note that there is no mutex required.
|
||||||
|
|
||||||
@@ -222,9 +232,6 @@ type histogram struct {
|
|||||||
counts []uint64
|
counts []uint64
|
||||||
|
|
||||||
labelPairs []*dto.LabelPair
|
labelPairs []*dto.LabelPair
|
||||||
|
|
||||||
sumBits uint64 // The bits of the float64 representing the sum of all observations.
|
|
||||||
count uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *histogram) Desc() *Desc {
|
func (h *histogram) Desc() *Desc {
|
||||||
@@ -342,3 +349,102 @@ func (m *HistogramVec) WithLabelValues(lvs ...string) Histogram {
|
|||||||
func (m *HistogramVec) With(labels Labels) Histogram {
|
func (m *HistogramVec) With(labels Labels) Histogram {
|
||||||
return m.MetricVec.With(labels).(Histogram)
|
return m.MetricVec.With(labels).(Histogram)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type constHistogram struct {
|
||||||
|
desc *Desc
|
||||||
|
count uint64
|
||||||
|
sum float64
|
||||||
|
buckets map[float64]uint64
|
||||||
|
labelPairs []*dto.LabelPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *constHistogram) Desc() *Desc {
|
||||||
|
return h.desc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *constHistogram) Write(out *dto.Metric) error {
|
||||||
|
his := &dto.Histogram{}
|
||||||
|
buckets := make([]*dto.Bucket, 0, len(h.buckets))
|
||||||
|
|
||||||
|
his.SampleCount = proto.Uint64(h.count)
|
||||||
|
his.SampleSum = proto.Float64(h.sum)
|
||||||
|
|
||||||
|
for upperBound, count := range h.buckets {
|
||||||
|
buckets = append(buckets, &dto.Bucket{
|
||||||
|
CumulativeCount: proto.Uint64(count),
|
||||||
|
UpperBound: proto.Float64(upperBound),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(buckets) > 0 {
|
||||||
|
sort.Sort(buckSort(buckets))
|
||||||
|
}
|
||||||
|
his.Bucket = buckets
|
||||||
|
|
||||||
|
out.Histogram = his
|
||||||
|
out.Label = h.labelPairs
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConstHistogram returns a metric representing a Prometheus histogram with
|
||||||
|
// fixed values for the count, sum, and bucket counts. As those parameters
|
||||||
|
// cannot be changed, the returned value does not implement the Histogram
|
||||||
|
// interface (but only the Metric interface). Users of this package will not
|
||||||
|
// have much use for it in regular operations. However, when implementing custom
|
||||||
|
// Collectors, it is useful as a throw-away metric that is generated on the fly
|
||||||
|
// to send it to Prometheus in the Collect method.
|
||||||
|
//
|
||||||
|
// buckets is a map of upper bounds to cumulative counts, excluding the +Inf
|
||||||
|
// bucket.
|
||||||
|
//
|
||||||
|
// NewConstHistogram returns an error if the length of labelValues is not
|
||||||
|
// consistent with the variable labels in Desc.
|
||||||
|
func NewConstHistogram(
|
||||||
|
desc *Desc,
|
||||||
|
count uint64,
|
||||||
|
sum float64,
|
||||||
|
buckets map[float64]uint64,
|
||||||
|
labelValues ...string,
|
||||||
|
) (Metric, error) {
|
||||||
|
if len(desc.variableLabels) != len(labelValues) {
|
||||||
|
return nil, errInconsistentCardinality
|
||||||
|
}
|
||||||
|
return &constHistogram{
|
||||||
|
desc: desc,
|
||||||
|
count: count,
|
||||||
|
sum: sum,
|
||||||
|
buckets: buckets,
|
||||||
|
labelPairs: makeLabelPairs(desc, labelValues),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustNewConstHistogram is a version of NewConstHistogram that panics where
|
||||||
|
// NewConstMetric would have returned an error.
|
||||||
|
func MustNewConstHistogram(
|
||||||
|
desc *Desc,
|
||||||
|
count uint64,
|
||||||
|
sum float64,
|
||||||
|
buckets map[float64]uint64,
|
||||||
|
labelValues ...string,
|
||||||
|
) Metric {
|
||||||
|
m, err := NewConstHistogram(desc, count, sum, buckets, labelValues...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
type buckSort []*dto.Bucket
|
||||||
|
|
||||||
|
func (s buckSort) Len() int {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s buckSort) Swap(i, j int) {
|
||||||
|
s[i], s[j] = s[j], s[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s buckSort) Less(i, j int) bool {
|
||||||
|
return s[i].GetUpperBound() < s[j].GetUpperBound()
|
||||||
|
}
|
||||||
|
@@ -124,6 +124,10 @@ func BenchmarkHistogramWrite8(b *testing.B) {
|
|||||||
var testBuckets = []float64{-2, -1, -0.5, 0, 0.5, 1, 2, math.Inf(+1)}
|
var testBuckets = []float64{-2, -1, -0.5, 0, 0.5, 1, 2, math.Inf(+1)}
|
||||||
|
|
||||||
func TestHistogramConcurrency(t *testing.T) {
|
func TestHistogramConcurrency(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping test in short mode.")
|
||||||
|
}
|
||||||
|
|
||||||
rand.Seed(42)
|
rand.Seed(42)
|
||||||
|
|
||||||
it := func(n uint32) bool {
|
it := func(n uint32) bool {
|
||||||
@@ -198,6 +202,10 @@ func TestHistogramConcurrency(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHistogramVecConcurrency(t *testing.T) {
|
func TestHistogramVecConcurrency(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping test in short mode.")
|
||||||
|
}
|
||||||
|
|
||||||
rand.Seed(42)
|
rand.Seed(42)
|
||||||
|
|
||||||
objectives := make([]float64, 0, len(DefObjectives))
|
objectives := make([]float64, 0, len(DefObjectives))
|
||||||
|
45
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/http.go
generated
vendored
45
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/http.go
generated
vendored
@@ -14,6 +14,9 @@
|
|||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -141,7 +144,18 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo
|
|||||||
urlLen = len(r.URL.String())
|
urlLen = len(r.URL.String())
|
||||||
}
|
}
|
||||||
go computeApproximateRequestSize(r, out, urlLen)
|
go computeApproximateRequestSize(r, out, urlLen)
|
||||||
handlerFunc(delegate, r)
|
|
||||||
|
_, cn := w.(http.CloseNotifier)
|
||||||
|
_, fl := w.(http.Flusher)
|
||||||
|
_, hj := w.(http.Hijacker)
|
||||||
|
_, rf := w.(io.ReaderFrom)
|
||||||
|
var rw http.ResponseWriter
|
||||||
|
if cn && fl && hj && rf {
|
||||||
|
rw = &fancyResponseWriterDelegator{delegate}
|
||||||
|
} else {
|
||||||
|
rw = delegate
|
||||||
|
}
|
||||||
|
handlerFunc(rw, r)
|
||||||
|
|
||||||
elapsed := float64(time.Since(now)) / float64(time.Microsecond)
|
elapsed := float64(time.Since(now)) / float64(time.Microsecond)
|
||||||
|
|
||||||
@@ -178,7 +192,7 @@ type responseWriterDelegator struct {
|
|||||||
|
|
||||||
handler, method string
|
handler, method string
|
||||||
status int
|
status int
|
||||||
written int
|
written int64
|
||||||
wroteHeader bool
|
wroteHeader bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +207,32 @@ func (r *responseWriterDelegator) Write(b []byte) (int, error) {
|
|||||||
r.WriteHeader(http.StatusOK)
|
r.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
n, err := r.ResponseWriter.Write(b)
|
n, err := r.ResponseWriter.Write(b)
|
||||||
r.written += n
|
r.written += int64(n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type fancyResponseWriterDelegator struct {
|
||||||
|
*responseWriterDelegator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fancyResponseWriterDelegator) CloseNotify() <-chan bool {
|
||||||
|
return f.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fancyResponseWriterDelegator) Flush() {
|
||||||
|
f.ResponseWriter.(http.Flusher).Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fancyResponseWriterDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
return f.ResponseWriter.(http.Hijacker).Hijack()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fancyResponseWriterDelegator) ReadFrom(r io.Reader) (int64, error) {
|
||||||
|
if !f.wroteHeader {
|
||||||
|
f.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
n, err := f.ResponseWriter.(io.ReaderFrom).ReadFrom(r)
|
||||||
|
f.written += n
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/metric.go
generated
vendored
2
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/metric.go
generated
vendored
@@ -19,6 +19,8 @@ import (
|
|||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const separatorByte byte = 255
|
||||||
|
|
||||||
// A Metric models a single sample value with its meta data being exported to
|
// A Metric models a single sample value with its meta data being exported to
|
||||||
// Prometheus. Implementers of Metric in this package inclued Gauge, Counter,
|
// Prometheus. Implementers of Metric in this package inclued Gauge, Counter,
|
||||||
// Untyped, and Summary. Users can implement their own Metric types, but that
|
// Untyped, and Summary. Users can implement their own Metric types, but that
|
||||||
|
106
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/registry.go
generated
vendored
106
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/registry.go
generated
vendored
@@ -33,13 +33,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"bitbucket.org/ww/goautoneg"
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/prometheus/common/expfmt"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
"github.com/prometheus/client_golang/text"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -170,6 +167,11 @@ func Unregister(c Collector) bool {
|
|||||||
// checks are performed, but no further consistency checks (which would require
|
// checks are performed, but no further consistency checks (which would require
|
||||||
// knowledge of a metric descriptor).
|
// knowledge of a metric descriptor).
|
||||||
//
|
//
|
||||||
|
// Sorting concerns: The caller is responsible for sorting the label pairs in
|
||||||
|
// each metric. However, the order of metrics will be sorted by the registry as
|
||||||
|
// it is required anyway after merging with the metric families collected
|
||||||
|
// conventionally.
|
||||||
|
//
|
||||||
// The function must be callable at any time and concurrently.
|
// The function must be callable at any time and concurrently.
|
||||||
func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) {
|
func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) {
|
||||||
defRegistry.metricFamilyInjectionHook = hook
|
defRegistry.metricFamilyInjectionHook = hook
|
||||||
@@ -341,7 +343,7 @@ func (r *registry) Push(job, instance, pushURL, method string) error {
|
|||||||
}
|
}
|
||||||
buf := r.getBuf()
|
buf := r.getBuf()
|
||||||
defer r.giveBuf(buf)
|
defer r.giveBuf(buf)
|
||||||
if _, err := r.writePB(buf, text.WriteProtoDelimited); err != nil {
|
if err := r.writePB(expfmt.NewEncoder(buf, expfmt.FmtProtoDelim)); err != nil {
|
||||||
if r.panicOnCollectError {
|
if r.panicOnCollectError {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -364,11 +366,11 @@ func (r *registry) Push(job, instance, pushURL, method string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *registry) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (r *registry) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
enc, contentType := chooseEncoder(req)
|
contentType := expfmt.Negotiate(req.Header)
|
||||||
buf := r.getBuf()
|
buf := r.getBuf()
|
||||||
defer r.giveBuf(buf)
|
defer r.giveBuf(buf)
|
||||||
writer, encoding := decorateWriter(req, buf)
|
writer, encoding := decorateWriter(req, buf)
|
||||||
if _, err := r.writePB(writer, enc); err != nil {
|
if err := r.writePB(expfmt.NewEncoder(writer, contentType)); err != nil {
|
||||||
if r.panicOnCollectError {
|
if r.panicOnCollectError {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -379,7 +381,7 @@ func (r *registry) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
closer.Close()
|
closer.Close()
|
||||||
}
|
}
|
||||||
header := w.Header()
|
header := w.Header()
|
||||||
header.Set(contentTypeHeader, contentType)
|
header.Set(contentTypeHeader, string(contentType))
|
||||||
header.Set(contentLengthHeader, fmt.Sprint(buf.Len()))
|
header.Set(contentLengthHeader, fmt.Sprint(buf.Len()))
|
||||||
if encoding != "" {
|
if encoding != "" {
|
||||||
header.Set(contentEncodingHeader, encoding)
|
header.Set(contentEncodingHeader, encoding)
|
||||||
@@ -387,7 +389,7 @@ func (r *registry) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
w.Write(buf.Bytes())
|
w.Write(buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registry) writePB(w io.Writer, writeEncoded encoder) (int, error) {
|
func (r *registry) writePB(encoder expfmt.Encoder) error {
|
||||||
var metricHashes map[uint64]struct{}
|
var metricHashes map[uint64]struct{}
|
||||||
if r.collectChecksEnabled {
|
if r.collectChecksEnabled {
|
||||||
metricHashes = make(map[uint64]struct{})
|
metricHashes = make(map[uint64]struct{})
|
||||||
@@ -439,7 +441,7 @@ func (r *registry) writePB(w io.Writer, writeEncoded encoder) (int, error) {
|
|||||||
// TODO: Consider different means of error reporting so
|
// TODO: Consider different means of error reporting so
|
||||||
// that a single erroneous metric could be skipped
|
// that a single erroneous metric could be skipped
|
||||||
// instead of blowing up the whole collection.
|
// instead of blowing up the whole collection.
|
||||||
return 0, fmt.Errorf("error collecting metric %v: %s", desc, err)
|
return fmt.Errorf("error collecting metric %v: %s", desc, err)
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case metricFamily.Type != nil:
|
case metricFamily.Type != nil:
|
||||||
@@ -455,11 +457,11 @@ func (r *registry) writePB(w io.Writer, writeEncoded encoder) (int, error) {
|
|||||||
case dtoMetric.Histogram != nil:
|
case dtoMetric.Histogram != nil:
|
||||||
metricFamily.Type = dto.MetricType_HISTOGRAM.Enum()
|
metricFamily.Type = dto.MetricType_HISTOGRAM.Enum()
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("empty metric collected: %s", dtoMetric)
|
return fmt.Errorf("empty metric collected: %s", dtoMetric)
|
||||||
}
|
}
|
||||||
if r.collectChecksEnabled {
|
if r.collectChecksEnabled {
|
||||||
if err := r.checkConsistency(metricFamily, dtoMetric, desc, metricHashes); err != nil {
|
if err := r.checkConsistency(metricFamily, dtoMetric, desc, metricHashes); err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
metricFamily.Metric = append(metricFamily.Metric, dtoMetric)
|
metricFamily.Metric = append(metricFamily.Metric, dtoMetric)
|
||||||
@@ -473,7 +475,7 @@ func (r *registry) writePB(w io.Writer, writeEncoded encoder) (int, error) {
|
|||||||
if r.collectChecksEnabled {
|
if r.collectChecksEnabled {
|
||||||
for _, m := range mf.Metric {
|
for _, m := range mf.Metric {
|
||||||
if err := r.checkConsistency(mf, m, nil, metricHashes); err != nil {
|
if err := r.checkConsistency(mf, m, nil, metricHashes); err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -482,7 +484,7 @@ func (r *registry) writePB(w io.Writer, writeEncoded encoder) (int, error) {
|
|||||||
for _, m := range mf.Metric {
|
for _, m := range mf.Metric {
|
||||||
if r.collectChecksEnabled {
|
if r.collectChecksEnabled {
|
||||||
if err := r.checkConsistency(existingMF, m, nil, metricHashes); err != nil {
|
if err := r.checkConsistency(existingMF, m, nil, metricHashes); err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
existingMF.Metric = append(existingMF.Metric, m)
|
existingMF.Metric = append(existingMF.Metric, m)
|
||||||
@@ -503,15 +505,12 @@ func (r *registry) writePB(w io.Writer, writeEncoded encoder) (int, error) {
|
|||||||
}
|
}
|
||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
|
|
||||||
var written int
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
w, err := writeEncoded(w, metricFamiliesByName[name])
|
if err := encoder.Encode(metricFamiliesByName[name]); err != nil {
|
||||||
written += w
|
return err
|
||||||
if err != nil {
|
|
||||||
return written, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return written, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *dto.Metric, desc *Desc, metricHashes map[uint64]struct{}) error {
|
func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *dto.Metric, desc *Desc, metricHashes map[uint64]struct{}) error {
|
||||||
@@ -520,10 +519,11 @@ func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *d
|
|||||||
if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil ||
|
if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil ||
|
||||||
metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil ||
|
metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil ||
|
||||||
metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil ||
|
metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil ||
|
||||||
|
metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil ||
|
||||||
metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil {
|
metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"collected metric %q is not a %s",
|
"collected metric %s %s is not a %s",
|
||||||
dtoMetric, metricFamily.Type,
|
metricFamily.GetName(), dtoMetric, metricFamily.GetType(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,19 +531,24 @@ func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *d
|
|||||||
h := fnv.New64a()
|
h := fnv.New64a()
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(metricFamily.GetName())
|
buf.WriteString(metricFamily.GetName())
|
||||||
buf.WriteByte(model.SeparatorByte)
|
buf.WriteByte(separatorByte)
|
||||||
h.Write(buf.Bytes())
|
h.Write(buf.Bytes())
|
||||||
|
// Make sure label pairs are sorted. We depend on it for the consistency
|
||||||
|
// check. Label pairs must be sorted by contract. But the point of this
|
||||||
|
// method is to check for contract violations. So we better do the sort
|
||||||
|
// now.
|
||||||
|
sort.Sort(LabelPairSorter(dtoMetric.Label))
|
||||||
for _, lp := range dtoMetric.Label {
|
for _, lp := range dtoMetric.Label {
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
buf.WriteString(lp.GetValue())
|
buf.WriteString(lp.GetValue())
|
||||||
buf.WriteByte(model.SeparatorByte)
|
buf.WriteByte(separatorByte)
|
||||||
h.Write(buf.Bytes())
|
h.Write(buf.Bytes())
|
||||||
}
|
}
|
||||||
metricHash := h.Sum64()
|
metricHash := h.Sum64()
|
||||||
if _, exists := metricHashes[metricHash]; exists {
|
if _, exists := metricHashes[metricHash]; exists {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"collected metric %q was collected before with the same name and label values",
|
"collected metric %s %s was collected before with the same name and label values",
|
||||||
dtoMetric,
|
metricFamily.GetName(), dtoMetric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
metricHashes[metricHash] = struct{}{}
|
metricHashes[metricHash] = struct{}{}
|
||||||
@@ -555,14 +560,14 @@ func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *d
|
|||||||
// Desc consistency with metric family.
|
// Desc consistency with metric family.
|
||||||
if metricFamily.GetName() != desc.fqName {
|
if metricFamily.GetName() != desc.fqName {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"collected metric %q has name %q but should have %q",
|
"collected metric %s %s has name %q but should have %q",
|
||||||
dtoMetric, metricFamily.GetName(), desc.fqName,
|
metricFamily.GetName(), dtoMetric, metricFamily.GetName(), desc.fqName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if metricFamily.GetHelp() != desc.help {
|
if metricFamily.GetHelp() != desc.help {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"collected metric %q has help %q but should have %q",
|
"collected metric %s %s has help %q but should have %q",
|
||||||
dtoMetric, metricFamily.GetHelp(), desc.help,
|
metricFamily.GetName(), dtoMetric, metricFamily.GetHelp(), desc.help,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,8 +581,8 @@ func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *d
|
|||||||
}
|
}
|
||||||
if len(lpsFromDesc) != len(dtoMetric.Label) {
|
if len(lpsFromDesc) != len(dtoMetric.Label) {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"labels in collected metric %q are inconsistent with descriptor %s",
|
"labels in collected metric %s %s are inconsistent with descriptor %s",
|
||||||
dtoMetric, desc,
|
metricFamily.GetName(), dtoMetric, desc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
sort.Sort(LabelPairSorter(lpsFromDesc))
|
sort.Sort(LabelPairSorter(lpsFromDesc))
|
||||||
@@ -586,8 +591,8 @@ func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *d
|
|||||||
if lpFromDesc.GetName() != lpFromMetric.GetName() ||
|
if lpFromDesc.GetName() != lpFromMetric.GetName() ||
|
||||||
lpFromDesc.Value != nil && lpFromDesc.GetValue() != lpFromMetric.GetValue() {
|
lpFromDesc.Value != nil && lpFromDesc.GetValue() != lpFromMetric.GetValue() {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"labels in collected metric %q are inconsistent with descriptor %s",
|
"labels in collected metric %s %s are inconsistent with descriptor %s",
|
||||||
dtoMetric, desc,
|
metricFamily.GetName(), dtoMetric, desc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -597,7 +602,10 @@ func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *d
|
|||||||
|
|
||||||
// Is the desc registered?
|
// Is the desc registered?
|
||||||
if _, exist := r.descIDs[desc.id]; !exist {
|
if _, exist := r.descIDs[desc.id]; !exist {
|
||||||
return fmt.Errorf("collected metric %q with unregistered descriptor %s", dtoMetric, desc)
|
return fmt.Errorf(
|
||||||
|
"collected metric %s %s with unregistered descriptor %s",
|
||||||
|
metricFamily.GetName(), dtoMetric, desc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -672,34 +680,6 @@ func newDefaultRegistry() *registry {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func chooseEncoder(req *http.Request) (encoder, string) {
|
|
||||||
accepts := goautoneg.ParseAccept(req.Header.Get(acceptHeader))
|
|
||||||
for _, accept := range accepts {
|
|
||||||
switch {
|
|
||||||
case accept.Type == "application" &&
|
|
||||||
accept.SubType == "vnd.google.protobuf" &&
|
|
||||||
accept.Params["proto"] == "io.prometheus.client.MetricFamily":
|
|
||||||
switch accept.Params["encoding"] {
|
|
||||||
case "delimited":
|
|
||||||
return text.WriteProtoDelimited, DelimitedTelemetryContentType
|
|
||||||
case "text":
|
|
||||||
return text.WriteProtoText, ProtoTextTelemetryContentType
|
|
||||||
case "compact-text":
|
|
||||||
return text.WriteProtoCompactText, ProtoCompactTextTelemetryContentType
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case accept.Type == "text" &&
|
|
||||||
accept.SubType == "plain" &&
|
|
||||||
(accept.Params["version"] == "0.0.4" || accept.Params["version"] == ""):
|
|
||||||
return text.MetricFamilyToText, TextTelemetryContentType
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return text.MetricFamilyToText, TextTelemetryContentType
|
|
||||||
}
|
|
||||||
|
|
||||||
// decorateWriter wraps a writer to handle gzip compression if requested. It
|
// decorateWriter wraps a writer to handle gzip compression if requested. It
|
||||||
// returns the decorated writer and the appropriate "Content-Encoding" header
|
// returns the decorated writer and the appropriate "Content-Encoding" header
|
||||||
// (which is empty if no compression is enabled).
|
// (which is empty if no compression is enabled).
|
||||||
|
20
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/registry_test.go
generated
vendored
20
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/registry_test.go
generated
vendored
@@ -68,14 +68,14 @@ func testHandler(t testing.TB) {
|
|||||||
Metric: []*dto.Metric{
|
Metric: []*dto.Metric{
|
||||||
{
|
{
|
||||||
Label: []*dto.LabelPair{
|
Label: []*dto.LabelPair{
|
||||||
{
|
|
||||||
Name: proto.String("externallabelname"),
|
|
||||||
Value: proto.String("externalval1"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: proto.String("externalconstname"),
|
Name: proto.String("externalconstname"),
|
||||||
Value: proto.String("externalconstvalue"),
|
Value: proto.String("externalconstvalue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: proto.String("externallabelname"),
|
||||||
|
Value: proto.String("externalval1"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Counter: &dto.Counter{
|
Counter: &dto.Counter{
|
||||||
Value: proto.Float64(1),
|
Value: proto.Float64(1),
|
||||||
@@ -100,27 +100,27 @@ func testHandler(t testing.TB) {
|
|||||||
externalMetricFamilyAsBytes := externalBuf.Bytes()
|
externalMetricFamilyAsBytes := externalBuf.Bytes()
|
||||||
externalMetricFamilyAsText := []byte(`# HELP externalname externaldocstring
|
externalMetricFamilyAsText := []byte(`# HELP externalname externaldocstring
|
||||||
# TYPE externalname counter
|
# TYPE externalname counter
|
||||||
externalname{externallabelname="externalval1",externalconstname="externalconstvalue"} 1
|
externalname{externalconstname="externalconstvalue",externallabelname="externalval1"} 1
|
||||||
`)
|
`)
|
||||||
externalMetricFamilyAsProtoText := []byte(`name: "externalname"
|
externalMetricFamilyAsProtoText := []byte(`name: "externalname"
|
||||||
help: "externaldocstring"
|
help: "externaldocstring"
|
||||||
type: COUNTER
|
type: COUNTER
|
||||||
metric: <
|
metric: <
|
||||||
label: <
|
|
||||||
name: "externallabelname"
|
|
||||||
value: "externalval1"
|
|
||||||
>
|
|
||||||
label: <
|
label: <
|
||||||
name: "externalconstname"
|
name: "externalconstname"
|
||||||
value: "externalconstvalue"
|
value: "externalconstvalue"
|
||||||
>
|
>
|
||||||
|
label: <
|
||||||
|
name: "externallabelname"
|
||||||
|
value: "externalval1"
|
||||||
|
>
|
||||||
counter: <
|
counter: <
|
||||||
value: 1
|
value: 1
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
|
|
||||||
`)
|
`)
|
||||||
externalMetricFamilyAsProtoCompactText := []byte(`name:"externalname" help:"externaldocstring" type:COUNTER metric:<label:<name:"externallabelname" value:"externalval1" > label:<name:"externalconstname" value:"externalconstvalue" > counter:<value:1 > >
|
externalMetricFamilyAsProtoCompactText := []byte(`name:"externalname" help:"externaldocstring" type:COUNTER metric:<label:<name:"externalconstname" value:"externalconstvalue" > label:<name:"externallabelname" value:"externalval1" > counter:<value:1 > >
|
||||||
`)
|
`)
|
||||||
|
|
||||||
expectedMetricFamily := &dto.MetricFamily{
|
expectedMetricFamily := &dto.MetricFamily{
|
||||||
|
102
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/summary.go
generated
vendored
102
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/summary.go
generated
vendored
@@ -25,10 +25,12 @@ import (
|
|||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// quantileLabel is used for the label that defines the quantile in a
|
||||||
|
// summary.
|
||||||
|
const quantileLabel = "quantile"
|
||||||
|
|
||||||
// A Summary captures individual observations from an event or sample stream and
|
// A Summary captures individual observations from an event or sample stream and
|
||||||
// summarizes them in a manner similar to traditional summary statistics: 1. sum
|
// summarizes them in a manner similar to traditional summary statistics: 1. sum
|
||||||
// of observations, 2. observation count, 3. rank estimations.
|
// of observations, 2. observation count, 3. rank estimations.
|
||||||
@@ -57,7 +59,7 @@ var (
|
|||||||
DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
|
DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
|
||||||
|
|
||||||
errQuantileLabelNotAllowed = fmt.Errorf(
|
errQuantileLabelNotAllowed = fmt.Errorf(
|
||||||
"%q is not allowed as label name in summaries", model.QuantileLabel,
|
"%q is not allowed as label name in summaries", quantileLabel,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -112,7 +114,9 @@ type SummaryOpts struct {
|
|||||||
ConstLabels Labels
|
ConstLabels Labels
|
||||||
|
|
||||||
// Objectives defines the quantile rank estimates with their respective
|
// Objectives defines the quantile rank estimates with their respective
|
||||||
// absolute error. The default value is DefObjectives.
|
// absolute error. If Objectives[q] = e, then the value reported
|
||||||
|
// for q will be the φ-quantile value for some φ between q-e and q+e.
|
||||||
|
// The default value is DefObjectives.
|
||||||
Objectives map[float64]float64
|
Objectives map[float64]float64
|
||||||
|
|
||||||
// MaxAge defines the duration for which an observation stays relevant
|
// MaxAge defines the duration for which an observation stays relevant
|
||||||
@@ -170,12 +174,12 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, n := range desc.variableLabels {
|
for _, n := range desc.variableLabels {
|
||||||
if n == model.QuantileLabel {
|
if n == quantileLabel {
|
||||||
panic(errQuantileLabelNotAllowed)
|
panic(errQuantileLabelNotAllowed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, lp := range desc.constLabelPairs {
|
for _, lp := range desc.constLabelPairs {
|
||||||
if lp.GetName() == model.QuantileLabel {
|
if lp.GetName() == quantileLabel {
|
||||||
panic(errQuantileLabelNotAllowed)
|
panic(errQuantileLabelNotAllowed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,3 +452,89 @@ func (m *SummaryVec) WithLabelValues(lvs ...string) Summary {
|
|||||||
func (m *SummaryVec) With(labels Labels) Summary {
|
func (m *SummaryVec) With(labels Labels) Summary {
|
||||||
return m.MetricVec.With(labels).(Summary)
|
return m.MetricVec.With(labels).(Summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type constSummary struct {
|
||||||
|
desc *Desc
|
||||||
|
count uint64
|
||||||
|
sum float64
|
||||||
|
quantiles map[float64]float64
|
||||||
|
labelPairs []*dto.LabelPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *constSummary) Desc() *Desc {
|
||||||
|
return s.desc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *constSummary) Write(out *dto.Metric) error {
|
||||||
|
sum := &dto.Summary{}
|
||||||
|
qs := make([]*dto.Quantile, 0, len(s.quantiles))
|
||||||
|
|
||||||
|
sum.SampleCount = proto.Uint64(s.count)
|
||||||
|
sum.SampleSum = proto.Float64(s.sum)
|
||||||
|
|
||||||
|
for rank, q := range s.quantiles {
|
||||||
|
qs = append(qs, &dto.Quantile{
|
||||||
|
Quantile: proto.Float64(rank),
|
||||||
|
Value: proto.Float64(q),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(qs) > 0 {
|
||||||
|
sort.Sort(quantSort(qs))
|
||||||
|
}
|
||||||
|
sum.Quantile = qs
|
||||||
|
|
||||||
|
out.Summary = sum
|
||||||
|
out.Label = s.labelPairs
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConstSummary returns a metric representing a Prometheus summary with fixed
|
||||||
|
// values for the count, sum, and quantiles. As those parameters cannot be
|
||||||
|
// changed, the returned value does not implement the Summary interface (but
|
||||||
|
// only the Metric interface). Users of this package will not have much use for
|
||||||
|
// it in regular operations. However, when implementing custom Collectors, it is
|
||||||
|
// useful as a throw-away metric that is generated on the fly to send it to
|
||||||
|
// Prometheus in the Collect method.
|
||||||
|
//
|
||||||
|
// quantiles maps ranks to quantile values. For example, a median latency of
|
||||||
|
// 0.23s and a 99th percentile latency of 0.56s would be expressed as:
|
||||||
|
// map[float64]float64{0.5: 0.23, 0.99: 0.56}
|
||||||
|
//
|
||||||
|
// NewConstSummary returns an error if the length of labelValues is not
|
||||||
|
// consistent with the variable labels in Desc.
|
||||||
|
func NewConstSummary(
|
||||||
|
desc *Desc,
|
||||||
|
count uint64,
|
||||||
|
sum float64,
|
||||||
|
quantiles map[float64]float64,
|
||||||
|
labelValues ...string,
|
||||||
|
) (Metric, error) {
|
||||||
|
if len(desc.variableLabels) != len(labelValues) {
|
||||||
|
return nil, errInconsistentCardinality
|
||||||
|
}
|
||||||
|
return &constSummary{
|
||||||
|
desc: desc,
|
||||||
|
count: count,
|
||||||
|
sum: sum,
|
||||||
|
quantiles: quantiles,
|
||||||
|
labelPairs: makeLabelPairs(desc, labelValues),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustNewConstSummary is a version of NewConstSummary that panics where
|
||||||
|
// NewConstMetric would have returned an error.
|
||||||
|
func MustNewConstSummary(
|
||||||
|
desc *Desc,
|
||||||
|
count uint64,
|
||||||
|
sum float64,
|
||||||
|
quantiles map[float64]float64,
|
||||||
|
labelValues ...string,
|
||||||
|
) Metric {
|
||||||
|
m, err := NewConstSummary(desc, count, sum, quantiles, labelValues...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
2
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/untyped.go
generated
vendored
2
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/untyped.go
generated
vendored
@@ -21,7 +21,7 @@ import "hash/fnv"
|
|||||||
// An Untyped metric works the same as a Gauge. The only difference is that to
|
// An Untyped metric works the same as a Gauge. The only difference is that to
|
||||||
// no type information is implied.
|
// no type information is implied.
|
||||||
//
|
//
|
||||||
// To create Gauge instances, use NewUntyped.
|
// To create Untyped instances, use NewUntyped.
|
||||||
type Untyped interface {
|
type Untyped interface {
|
||||||
Metric
|
Metric
|
||||||
Collector
|
Collector
|
||||||
|
6
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/value.go
generated
vendored
6
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/value.go
generated
vendored
@@ -43,11 +43,15 @@ var errInconsistentCardinality = errors.New("inconsistent label cardinality")
|
|||||||
// ValueType. This is a low-level building block used by the library to back the
|
// ValueType. This is a low-level building block used by the library to back the
|
||||||
// implementations of Counter, Gauge, and Untyped.
|
// implementations of Counter, Gauge, and Untyped.
|
||||||
type value struct {
|
type value struct {
|
||||||
|
// valBits containst the bits of the represented float64 value. It has
|
||||||
|
// to go first in the struct to guarantee alignment for atomic
|
||||||
|
// operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||||
|
valBits uint64
|
||||||
|
|
||||||
SelfCollector
|
SelfCollector
|
||||||
|
|
||||||
desc *Desc
|
desc *Desc
|
||||||
valType ValueType
|
valType ValueType
|
||||||
valBits uint64 // These are the bits of the represented float64 value.
|
|
||||||
labelPairs []*dto.LabelPair
|
labelPairs []*dto.LabelPair
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/vec.go
generated
vendored
10
Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus/vec.go
generated
vendored
@@ -58,6 +58,11 @@ func (m *MetricVec) Collect(ch chan<- Metric) {
|
|||||||
// GetMetricWithLabelValues returns the Metric for the given slice of label
|
// GetMetricWithLabelValues returns the Metric for the given slice of label
|
||||||
// values (same order as the VariableLabels in Desc). If that combination of
|
// values (same order as the VariableLabels in Desc). If that combination of
|
||||||
// label values is accessed for the first time, a new Metric is created.
|
// label values is accessed for the first time, a new Metric is created.
|
||||||
|
//
|
||||||
|
// It is possible to call this method without using the returned Metric to only
|
||||||
|
// create the new Metric but leave it at its start value (e.g. a Summary or
|
||||||
|
// Histogram without any observations). See also the SummaryVec example.
|
||||||
|
//
|
||||||
// Keeping the Metric for later use is possible (and should be considered if
|
// Keeping the Metric for later use is possible (and should be considered if
|
||||||
// performance is critical), but keep in mind that Reset, DeleteLabelValues and
|
// performance is critical), but keep in mind that Reset, DeleteLabelValues and
|
||||||
// Delete can be used to delete the Metric from the MetricVec. In that case, the
|
// Delete can be used to delete the Metric from the MetricVec. In that case, the
|
||||||
@@ -87,8 +92,9 @@ func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
|
|||||||
|
|
||||||
// GetMetricWith returns the Metric for the given Labels map (the label names
|
// GetMetricWith returns the Metric for the given Labels map (the label names
|
||||||
// must match those of the VariableLabels in Desc). If that label map is
|
// must match those of the VariableLabels in Desc). If that label map is
|
||||||
// accessed for the first time, a new Metric is created. Implications of keeping
|
// accessed for the first time, a new Metric is created. Implications of
|
||||||
// the Metric are the same as for GetMetricWithLabelValues.
|
// creating a Metric without using it and keeping the Metric for later use are
|
||||||
|
// the same as for GetMetricWithLabelValues.
|
||||||
//
|
//
|
||||||
// An error is returned if the number and names of the Labels are inconsistent
|
// An error is returned if the number and names of the Labels are inconsistent
|
||||||
// with those of the VariableLabels in Desc.
|
// with those of the VariableLabels in Desc.
|
||||||
|
43
Godeps/_workspace/src/github.com/prometheus/client_golang/text/proto.go
generated
vendored
43
Godeps/_workspace/src/github.com/prometheus/client_golang/text/proto.go
generated
vendored
@@ -1,43 +0,0 @@
|
|||||||
// 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 text
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WriteProtoDelimited writes the MetricFamily to the writer in delimited
|
|
||||||
// protobuf format and returns the number of bytes written and any error
|
|
||||||
// encountered.
|
|
||||||
func WriteProtoDelimited(w io.Writer, p *dto.MetricFamily) (int, error) {
|
|
||||||
return pbutil.WriteDelimited(w, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteProtoText writes the MetricFamily to the writer in text format and
|
|
||||||
// returns the number of bytes written and any error encountered.
|
|
||||||
func WriteProtoText(w io.Writer, p *dto.MetricFamily) (int, error) {
|
|
||||||
return fmt.Fprintf(w, "%s\n", proto.MarshalTextString(p))
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteProtoCompactText writes the MetricFamily to the writer in compact text
|
|
||||||
// format and returns the number of bytes written and any error encountered.
|
|
||||||
func WriteProtoCompactText(w io.Writer, p *dto.MetricFamily) (int, error) {
|
|
||||||
return fmt.Fprintf(w, "%s\n", p)
|
|
||||||
}
|
|
BIN
Godeps/_workspace/src/github.com/prometheus/client_golang/text/testdata/protobuf
generated
vendored
BIN
Godeps/_workspace/src/github.com/prometheus/client_golang/text/testdata/protobuf
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/github.com/prometheus/client_golang/text/testdata/protobuf.gz
generated
vendored
BIN
Godeps/_workspace/src/github.com/prometheus/client_golang/text/testdata/protobuf.gz
generated
vendored
Binary file not shown.
BIN
Godeps/_workspace/src/github.com/prometheus/client_golang/text/testdata/text.gz
generated
vendored
BIN
Godeps/_workspace/src/github.com/prometheus/client_golang/text/testdata/text.gz
generated
vendored
Binary file not shown.
@@ -11,7 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package text
|
package expfmt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -19,11 +19,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
dto "github.com/prometheus/client_model/go"
|
|
||||||
|
|
||||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||||
|
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var parser TextParser
|
||||||
|
|
||||||
// Benchmarks to show how much penalty text format parsing actually inflicts.
|
// Benchmarks to show how much penalty text format parsing actually inflicts.
|
||||||
//
|
//
|
||||||
// Example results on Linux 3.13.0, Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz, go1.4.
|
// Example results on Linux 3.13.0, Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz, go1.4.
|
388
Godeps/_workspace/src/github.com/prometheus/common/expfmt/decode.go
generated
vendored
Normal file
388
Godeps/_workspace/src/github.com/prometheus/common/expfmt/decode.go
generated
vendored
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
// Copyright 2015 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 expfmt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
|
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decoder types decode an input stream into metric families.
|
||||||
|
type Decoder interface {
|
||||||
|
Decode(*dto.MetricFamily) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type DecodeOptions struct {
|
||||||
|
// Timestamp is added to each value from the stream that has no explicit timestamp set.
|
||||||
|
Timestamp model.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a new decoder based on the HTTP header.
|
||||||
|
func NewDecoder(r io.Reader, h http.Header) (Decoder, error) {
|
||||||
|
ct := h.Get(hdrContentType)
|
||||||
|
|
||||||
|
mediatype, params, err := mime.ParseMediaType(ct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid Content-Type header %q: %s", ct, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
protoType = ProtoType + "/" + ProtoSubType
|
||||||
|
textType = "text/plain"
|
||||||
|
)
|
||||||
|
|
||||||
|
switch mediatype {
|
||||||
|
case protoType:
|
||||||
|
if p := params["proto"]; p != ProtoProtocol {
|
||||||
|
return nil, fmt.Errorf("unrecognized protocol message %s", p)
|
||||||
|
}
|
||||||
|
if e := params["encoding"]; e != "delimited" {
|
||||||
|
return nil, fmt.Errorf("unsupported encoding %s", e)
|
||||||
|
}
|
||||||
|
return &protoDecoder{r: r}, nil
|
||||||
|
|
||||||
|
case textType:
|
||||||
|
if v, ok := params["version"]; ok && v != "0.0.4" {
|
||||||
|
return nil, fmt.Errorf("unrecognized protocol version %s", v)
|
||||||
|
}
|
||||||
|
return &textDecoder{r: r}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported media type %q, expected %q or %q", mediatype, protoType, textType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// protoDecoder implements the Decoder interface for protocol buffers.
|
||||||
|
type protoDecoder struct {
|
||||||
|
r io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode implements the Decoder interface.
|
||||||
|
func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
|
||||||
|
_, err := pbutil.ReadDelimited(d.r, v)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// textDecoder implements the Decoder interface for the text protcol.
|
||||||
|
type textDecoder struct {
|
||||||
|
r io.Reader
|
||||||
|
p TextParser
|
||||||
|
fams []*dto.MetricFamily
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode implements the Decoder interface.
|
||||||
|
func (d *textDecoder) Decode(v *dto.MetricFamily) error {
|
||||||
|
// TODO(fabxc): Wrap this as a line reader to make streaming safer.
|
||||||
|
if len(d.fams) == 0 {
|
||||||
|
// No cached metric families, read everything and parse metrics.
|
||||||
|
fams, err := d.p.TextToMetricFamilies(d.r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(fams) == 0 {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
|
for _, f := range fams {
|
||||||
|
d.fams = append(d.fams, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*v = *d.fams[len(d.fams)-1]
|
||||||
|
d.fams = d.fams[:len(d.fams)-1]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SampleDecoder struct {
|
||||||
|
Dec Decoder
|
||||||
|
Opts *DecodeOptions
|
||||||
|
|
||||||
|
f dto.MetricFamily
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sd *SampleDecoder) Decode(s *model.Vector) error {
|
||||||
|
if err := sd.Dec.Decode(&sd.f); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*s = extractSamples(&sd.f, sd.Opts)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract samples builds a slice of samples from the provided metric families.
|
||||||
|
func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) model.Vector {
|
||||||
|
var all model.Vector
|
||||||
|
for _, f := range fams {
|
||||||
|
all = append(all, extractSamples(f, o)...)
|
||||||
|
}
|
||||||
|
return all
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractSamples(f *dto.MetricFamily, o *DecodeOptions) model.Vector {
|
||||||
|
switch f.GetType() {
|
||||||
|
case dto.MetricType_COUNTER:
|
||||||
|
return extractCounter(o, f)
|
||||||
|
case dto.MetricType_GAUGE:
|
||||||
|
return extractGauge(o, f)
|
||||||
|
case dto.MetricType_SUMMARY:
|
||||||
|
return extractSummary(o, f)
|
||||||
|
case dto.MetricType_UNTYPED:
|
||||||
|
return extractUntyped(o, f)
|
||||||
|
case dto.MetricType_HISTOGRAM:
|
||||||
|
return extractHistogram(o, f)
|
||||||
|
}
|
||||||
|
panic("expfmt.extractSamples: unknown metric family type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||||
|
samples := make(model.Vector, 0, len(f.Metric))
|
||||||
|
|
||||||
|
for _, m := range f.Metric {
|
||||||
|
if m.Counter == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+1)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
||||||
|
|
||||||
|
smpl := &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(m.Counter.GetValue()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.TimestampMs != nil {
|
||||||
|
smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||||
|
} else {
|
||||||
|
smpl.Timestamp = o.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = append(samples, smpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractGauge(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||||
|
samples := make(model.Vector, 0, len(f.Metric))
|
||||||
|
|
||||||
|
for _, m := range f.Metric {
|
||||||
|
if m.Gauge == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+1)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
||||||
|
|
||||||
|
smpl := &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(m.Gauge.GetValue()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.TimestampMs != nil {
|
||||||
|
smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||||
|
} else {
|
||||||
|
smpl.Timestamp = o.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = append(samples, smpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractUntyped(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||||
|
samples := make(model.Vector, 0, len(f.Metric))
|
||||||
|
|
||||||
|
for _, m := range f.Metric {
|
||||||
|
if m.Untyped == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+1)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
||||||
|
|
||||||
|
smpl := &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(m.Untyped.GetValue()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.TimestampMs != nil {
|
||||||
|
smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||||
|
} else {
|
||||||
|
smpl.Timestamp = o.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = append(samples, smpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractSummary(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||||
|
samples := make(model.Vector, 0, len(f.Metric))
|
||||||
|
|
||||||
|
for _, m := range f.Metric {
|
||||||
|
if m.Summary == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp := o.Timestamp
|
||||||
|
if m.TimestampMs != nil {
|
||||||
|
timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, q := range m.Summary.Quantile {
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+2)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
// BUG(matt): Update other names to "quantile".
|
||||||
|
lset[model.LabelName(model.QuantileLabel)] = model.LabelValue(fmt.Sprint(q.GetQuantile()))
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
||||||
|
|
||||||
|
samples = append(samples, &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(q.GetValue()),
|
||||||
|
Timestamp: timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Summary.SampleSum != nil {
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+1)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
|
||||||
|
|
||||||
|
samples = append(samples, &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(m.Summary.GetSampleSum()),
|
||||||
|
Timestamp: timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Summary.SampleCount != nil {
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+1)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
|
||||||
|
|
||||||
|
samples = append(samples, &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(m.Summary.GetSampleCount()),
|
||||||
|
Timestamp: timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractHistogram(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||||
|
samples := make(model.Vector, 0, len(f.Metric))
|
||||||
|
|
||||||
|
for _, m := range f.Metric {
|
||||||
|
if m.Histogram == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp := o.Timestamp
|
||||||
|
if m.TimestampMs != nil {
|
||||||
|
timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||||
|
}
|
||||||
|
|
||||||
|
infSeen := false
|
||||||
|
|
||||||
|
for _, q := range m.Histogram.Bucket {
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+2)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.LabelName(model.BucketLabel)] = model.LabelValue(fmt.Sprint(q.GetUpperBound()))
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
|
||||||
|
|
||||||
|
if math.IsInf(q.GetUpperBound(), +1) {
|
||||||
|
infSeen = true
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = append(samples, &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(q.GetCumulativeCount()),
|
||||||
|
Timestamp: timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Histogram.SampleSum != nil {
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+1)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
|
||||||
|
|
||||||
|
samples = append(samples, &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(m.Histogram.GetSampleSum()),
|
||||||
|
Timestamp: timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Histogram.SampleCount != nil {
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+1)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
|
||||||
|
|
||||||
|
count := &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: model.SampleValue(m.Histogram.GetSampleCount()),
|
||||||
|
Timestamp: timestamp,
|
||||||
|
}
|
||||||
|
samples = append(samples, count)
|
||||||
|
|
||||||
|
if !infSeen {
|
||||||
|
// Append a infinity bucket sample.
|
||||||
|
lset := make(model.LabelSet, len(m.Label)+2)
|
||||||
|
for _, p := range m.Label {
|
||||||
|
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||||
|
}
|
||||||
|
lset[model.LabelName(model.BucketLabel)] = model.LabelValue("+Inf")
|
||||||
|
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
|
||||||
|
|
||||||
|
samples = append(samples, &model.Sample{
|
||||||
|
Metric: model.Metric(lset),
|
||||||
|
Value: count.Value,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples
|
||||||
|
}
|
341
Godeps/_workspace/src/github.com/prometheus/common/expfmt/decode_test.go
generated
vendored
Normal file
341
Godeps/_workspace/src/github.com/prometheus/common/expfmt/decode_test.go
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
// Copyright 2015 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 expfmt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTextDecoder(t *testing.T) {
|
||||||
|
var (
|
||||||
|
ts = model.Now()
|
||||||
|
in = `
|
||||||
|
# Only a quite simple scenario with two metric families.
|
||||||
|
# More complicated tests of the parser itself can be found in the text package.
|
||||||
|
# TYPE mf2 counter
|
||||||
|
mf2 3
|
||||||
|
mf1{label="value1"} -3.14 123456
|
||||||
|
mf1{label="value2"} 42
|
||||||
|
mf2 4
|
||||||
|
`
|
||||||
|
out = model.Vector{
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "mf1",
|
||||||
|
"label": "value1",
|
||||||
|
},
|
||||||
|
Value: -3.14,
|
||||||
|
Timestamp: 123456,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "mf1",
|
||||||
|
"label": "value2",
|
||||||
|
},
|
||||||
|
Value: 42,
|
||||||
|
Timestamp: ts,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "mf2",
|
||||||
|
},
|
||||||
|
Value: 3,
|
||||||
|
Timestamp: ts,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "mf2",
|
||||||
|
},
|
||||||
|
Value: 4,
|
||||||
|
Timestamp: ts,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
dec := &SampleDecoder{
|
||||||
|
Dec: &textDecoder{r: strings.NewReader(in)},
|
||||||
|
Opts: &DecodeOptions{
|
||||||
|
Timestamp: ts,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var all model.Vector
|
||||||
|
for {
|
||||||
|
var smpls model.Vector
|
||||||
|
err := dec.Decode(&smpls)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
all = append(all, smpls...)
|
||||||
|
}
|
||||||
|
sort.Sort(all)
|
||||||
|
sort.Sort(out)
|
||||||
|
if !reflect.DeepEqual(all, out) {
|
||||||
|
t.Fatalf("output does not match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProtoDecoder(t *testing.T) {
|
||||||
|
|
||||||
|
var testTime = model.Now()
|
||||||
|
|
||||||
|
scenarios := []struct {
|
||||||
|
in string
|
||||||
|
expected model.Vector
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_label_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@",
|
||||||
|
expected: model.Vector{
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_count",
|
||||||
|
"some_label_name": "some_label_value",
|
||||||
|
},
|
||||||
|
Value: -42,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_count",
|
||||||
|
"another_label_name": "another_label_value",
|
||||||
|
},
|
||||||
|
Value: 84,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: "\xb9\x01\n\rrequest_count\x12\x12Number of requests\x18\x02\"O\n#\n\x0fsome_label_name\x12\x10some_label_value\"(\x1a\x12\t\xaeG\xe1z\x14\xae\xef?\x11\x00\x00\x00\x00\x00\x00E\xc0\x1a\x12\t+\x87\x16\xd9\xce\xf7\xef?\x11\x00\x00\x00\x00\x00\x00U\xc0\"A\n)\n\x12another_label_name\x12\x13another_label_value\"\x14\x1a\x12\t\x00\x00\x00\x00\x00\x00\xe0?\x11\x00\x00\x00\x00\x00\x00$@",
|
||||||
|
expected: model.Vector{
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_count",
|
||||||
|
"some_label_name": "some_label_value",
|
||||||
|
"quantile": "0.99",
|
||||||
|
},
|
||||||
|
Value: -42,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_count",
|
||||||
|
"some_label_name": "some_label_value",
|
||||||
|
"quantile": "0.999",
|
||||||
|
},
|
||||||
|
Value: -84,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_count",
|
||||||
|
"another_label_name": "another_label_value",
|
||||||
|
"quantile": "0.5",
|
||||||
|
},
|
||||||
|
Value: 10,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: "\x8d\x01\n\x1drequest_duration_microseconds\x12\x15The response latency.\x18\x04\"S:Q\b\x85\x15\x11\xcd\xcc\xccL\x8f\xcb:A\x1a\v\b{\x11\x00\x00\x00\x00\x00\x00Y@\x1a\f\b\x9c\x03\x11\x00\x00\x00\x00\x00\x00^@\x1a\f\b\xd0\x04\x11\x00\x00\x00\x00\x00\x00b@\x1a\f\b\xf4\v\x11\x9a\x99\x99\x99\x99\x99e@\x1a\f\b\x85\x15\x11\x00\x00\x00\x00\x00\x00\xf0\u007f",
|
||||||
|
expected: model.Vector{
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||||
|
"le": "100",
|
||||||
|
},
|
||||||
|
Value: 123,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||||
|
"le": "120",
|
||||||
|
},
|
||||||
|
Value: 412,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||||
|
"le": "144",
|
||||||
|
},
|
||||||
|
Value: 592,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||||
|
"le": "172.8",
|
||||||
|
},
|
||||||
|
Value: 1524,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||||
|
"le": "+Inf",
|
||||||
|
},
|
||||||
|
Value: 2693,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_duration_microseconds_sum",
|
||||||
|
},
|
||||||
|
Value: 1756047.3,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_duration_microseconds_count",
|
||||||
|
},
|
||||||
|
Value: 2693,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// The metric type is unset in this protobuf, which needs to be handled
|
||||||
|
// correctly by the decoder.
|
||||||
|
in: "\x1c\n\rrequest_count\"\v\x1a\t\t\x00\x00\x00\x00\x00\x00\xf0?",
|
||||||
|
expected: model.Vector{
|
||||||
|
&model.Sample{
|
||||||
|
Metric: model.Metric{
|
||||||
|
model.MetricNameLabel: "request_count",
|
||||||
|
},
|
||||||
|
Value: 1,
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, scenario := range scenarios {
|
||||||
|
dec := &SampleDecoder{
|
||||||
|
Dec: &protoDecoder{r: strings.NewReader(scenario.in)},
|
||||||
|
Opts: &DecodeOptions{
|
||||||
|
Timestamp: testTime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var all model.Vector
|
||||||
|
for {
|
||||||
|
var smpls model.Vector
|
||||||
|
err := dec.Decode(&smpls)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
all = append(all, smpls...)
|
||||||
|
}
|
||||||
|
sort.Sort(all)
|
||||||
|
sort.Sort(scenario.expected)
|
||||||
|
if !reflect.DeepEqual(all, scenario.expected) {
|
||||||
|
t.Fatalf("output does not match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDiscriminatorHTTPHeader(t testing.TB) {
|
||||||
|
var scenarios = []struct {
|
||||||
|
input map[string]string
|
||||||
|
output Decoder
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`},
|
||||||
|
output: &protoDecoder{},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`},
|
||||||
|
output: nil,
|
||||||
|
err: errors.New("unrecognized protocol message illegal"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`},
|
||||||
|
output: nil,
|
||||||
|
err: errors.New("unsupported encoding illegal"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: map[string]string{"Content-Type": `text/plain; version=0.0.4`},
|
||||||
|
output: &textDecoder{},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: map[string]string{"Content-Type": `text/plain`},
|
||||||
|
output: &textDecoder{},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: map[string]string{"Content-Type": `text/plain; version=0.0.3`},
|
||||||
|
output: nil,
|
||||||
|
err: errors.New("unrecognized protocol version 0.0.3"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, scenario := range scenarios {
|
||||||
|
var header http.Header
|
||||||
|
|
||||||
|
if len(scenario.input) > 0 {
|
||||||
|
header = http.Header{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range scenario.input {
|
||||||
|
header.Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := NewDecoder(nil, header)
|
||||||
|
|
||||||
|
if scenario.err != err {
|
||||||
|
if scenario.err != nil && err != nil {
|
||||||
|
if scenario.err.Error() != err.Error() {
|
||||||
|
t.Errorf("%d. expected %s, got %s", i, scenario.err, err)
|
||||||
|
}
|
||||||
|
} else if scenario.err != nil || err != nil {
|
||||||
|
t.Errorf("%d. expected %s, got %s", i, scenario.err, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(scenario.output, actual) {
|
||||||
|
t.Errorf("%d. expected %s, got %s", i, scenario.output, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDiscriminatorHTTPHeader(t *testing.T) {
|
||||||
|
testDiscriminatorHTTPHeader(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDiscriminatorHTTPHeader(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
testDiscriminatorHTTPHeader(b)
|
||||||
|
}
|
||||||
|
}
|
88
Godeps/_workspace/src/github.com/prometheus/common/expfmt/encode.go
generated
vendored
Normal file
88
Godeps/_workspace/src/github.com/prometheus/common/expfmt/encode.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
// Copyright 2015 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 expfmt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"bitbucket.org/ww/goautoneg"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||||
|
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encoder types encode metric families into an underlying wire protocol.
|
||||||
|
type Encoder interface {
|
||||||
|
Encode(*dto.MetricFamily) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type encoder func(*dto.MetricFamily) error
|
||||||
|
|
||||||
|
func (e encoder) Encode(v *dto.MetricFamily) error {
|
||||||
|
return e(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negotiate returns the Content-Type based on the given Accept header.
|
||||||
|
// If no appropriate accepted type is found, FmtText is returned.
|
||||||
|
func Negotiate(h http.Header) Format {
|
||||||
|
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
|
||||||
|
// Check for protocol buffer
|
||||||
|
if ac.Type == ProtoType && ac.SubType == ProtoSubType && ac.Params["proto"] == ProtoProtocol {
|
||||||
|
switch ac.Params["encoding"] {
|
||||||
|
case "delimited":
|
||||||
|
return FmtProtoDelim
|
||||||
|
case "text":
|
||||||
|
return FmtProtoText
|
||||||
|
case "compact-text":
|
||||||
|
return FmtProtoCompact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check for text format.
|
||||||
|
ver := ac.Params["version"]
|
||||||
|
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
||||||
|
return FmtText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FmtText
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns a new encoder based on content type negotiation.
|
||||||
|
func NewEncoder(w io.Writer, format Format) Encoder {
|
||||||
|
switch format {
|
||||||
|
case FmtProtoDelim:
|
||||||
|
return encoder(func(v *dto.MetricFamily) error {
|
||||||
|
_, err := pbutil.WriteDelimited(w, v)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
case FmtProtoCompact:
|
||||||
|
return encoder(func(v *dto.MetricFamily) error {
|
||||||
|
_, err := fmt.Fprintln(w, v.String())
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
case FmtProtoText:
|
||||||
|
return encoder(func(v *dto.MetricFamily) error {
|
||||||
|
_, err := fmt.Fprintln(w, proto.MarshalTextString(v))
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
case FmtText:
|
||||||
|
return encoder(func(v *dto.MetricFamily) error {
|
||||||
|
_, err := MetricFamilyToText(w, v)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
panic("expfmt.NewEncoder: unknown format")
|
||||||
|
}
|
37
Godeps/_workspace/src/github.com/prometheus/common/expfmt/expfmt.go
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/prometheus/common/expfmt/expfmt.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// A package for reading and writing Prometheus metrics.
|
||||||
|
package expfmt
|
||||||
|
|
||||||
|
type Format string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TextVersion = "0.0.4"
|
||||||
|
|
||||||
|
ProtoType = `application`
|
||||||
|
ProtoSubType = `vnd.google.protobuf`
|
||||||
|
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
||||||
|
ProtoFmt = ProtoType + "/" + ProtoSubType + "; proto=" + ProtoProtocol + ";"
|
||||||
|
|
||||||
|
// The Content-Type values for the different wire protocols.
|
||||||
|
FmtText Format = `text/plain; version=` + TextVersion
|
||||||
|
FmtProtoDelim Format = ProtoFmt + ` encoding=delimited`
|
||||||
|
FmtProtoText Format = ProtoFmt + ` encoding=text`
|
||||||
|
FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hdrContentType = "Content-Type"
|
||||||
|
hdrAccept = "Accept"
|
||||||
|
)
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2013 The Prometheus Authors
|
// Copyright 2014 The Prometheus Authors
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
@@ -11,26 +11,26 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package model
|
// Build only when actually fuzzing
|
||||||
|
// +build gofuzz
|
||||||
|
|
||||||
import (
|
package expfmt
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A LabelValue is an associated value for a LabelName.
|
import "bytes"
|
||||||
type LabelValue string
|
|
||||||
|
|
||||||
// LabelValues is a sortable LabelValue slice. It implements sort.Interface.
|
// Fuzz text metric parser with with github.com/dvyukov/go-fuzz:
|
||||||
type LabelValues []LabelValue
|
//
|
||||||
|
// go-fuzz-build github.com/prometheus/client_golang/text
|
||||||
|
// go-fuzz -bin text-fuzz.zip -workdir fuzz
|
||||||
|
//
|
||||||
|
// Further input samples should go in the folder fuzz/corpus.
|
||||||
|
func Fuzz(in []byte) int {
|
||||||
|
parser := TextParser{}
|
||||||
|
_, err := parser.TextToMetricFamilies(bytes.NewReader(in))
|
||||||
|
|
||||||
func (l LabelValues) Len() int {
|
if err != nil {
|
||||||
return len(l)
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l LabelValues) Less(i, j int) bool {
|
return 1
|
||||||
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]
|
|
||||||
}
|
}
|
2
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_0
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_0
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
|
6
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_1
generated
vendored
Normal file
6
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_1
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
minimal_metric 1.234
|
||||||
|
another_metric -3e3 103948
|
||||||
|
# Even that:
|
||||||
|
no_labels{} 3
|
||||||
|
# HELP line for non-existing metric will be ignored.
|
12
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_2
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_2
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
# A normal comment.
|
||||||
|
#
|
||||||
|
# TYPE name counter
|
||||||
|
name{labelname="val1",basename="basevalue"} NaN
|
||||||
|
name {labelname="val2",basename="base\"v\\al\nue"} 0.23 1234567890
|
||||||
|
# HELP name two-line\n doc str\\ing
|
||||||
|
|
||||||
|
# HELP name2 doc str"ing 2
|
||||||
|
# TYPE name2 gauge
|
||||||
|
name2{labelname="val2" ,basename = "basevalue2" } +Inf 54321
|
||||||
|
name2{ labelname = "val1" , }-Inf
|
22
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_3
generated
vendored
Normal file
22
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_3
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
# TYPE my_summary summary
|
||||||
|
my_summary{n1="val1",quantile="0.5"} 110
|
||||||
|
decoy -1 -2
|
||||||
|
my_summary{n1="val1",quantile="0.9"} 140 1
|
||||||
|
my_summary_count{n1="val1"} 42
|
||||||
|
# Latest timestamp wins in case of a summary.
|
||||||
|
my_summary_sum{n1="val1"} 4711 2
|
||||||
|
fake_sum{n1="val1"} 2001
|
||||||
|
# TYPE another_summary summary
|
||||||
|
another_summary_count{n2="val2",n1="val1"} 20
|
||||||
|
my_summary_count{n2="val2",n1="val1"} 5 5
|
||||||
|
another_summary{n1="val1",n2="val2",quantile=".3"} -1.2
|
||||||
|
my_summary_sum{n1="val2"} 08 15
|
||||||
|
my_summary{n1="val3", quantile="0.2"} 4711
|
||||||
|
my_summary{n1="val1",n2="val2",quantile="-12.34",} NaN
|
||||||
|
# some
|
||||||
|
# funny comments
|
||||||
|
# HELP
|
||||||
|
# HELP
|
||||||
|
# HELP my_summary
|
||||||
|
# HELP my_summary
|
10
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_4
generated
vendored
Normal file
10
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_4
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
# HELP request_duration_microseconds The response latency.
|
||||||
|
# TYPE request_duration_microseconds histogram
|
||||||
|
request_duration_microseconds_bucket{le="100"} 123
|
||||||
|
request_duration_microseconds_bucket{le="120"} 412
|
||||||
|
request_duration_microseconds_bucket{le="144"} 592
|
||||||
|
request_duration_microseconds_bucket{le="172.8"} 1524
|
||||||
|
request_duration_microseconds_bucket{le="+Inf"} 2693
|
||||||
|
request_duration_microseconds_sum 1.7560473e+06
|
||||||
|
request_duration_microseconds_count 2693
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_0
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_0
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
bla 3.14
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_1
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_1
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{label="\t"} 3.14
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_10
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_10
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{label="bla"} 3.14 2 3
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_11
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_11
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{label="bla"} blubb
|
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_12
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_12
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
# HELP metric one
|
||||||
|
# HELP metric two
|
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_13
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_13
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
# TYPE metric counter
|
||||||
|
# TYPE metric untyped
|
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_14
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_14
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
metric 4.12
|
||||||
|
# TYPE metric counter
|
2
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_15
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_15
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
# TYPE metric bla
|
2
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_16
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_16
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
# TYPE met-ric
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_17
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_17
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@invalidmetric{label="bla"} 3.14 2
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_18
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_18
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{label="bla"} 3.14 2
|
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_19
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_19
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
# TYPE metric histogram
|
||||||
|
metric_bucket{le="bla"} 3.14
|
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_2
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_2
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
metric{label="new
|
||||||
|
line"} 3.14
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_3
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_3
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{@="bla"} 3.14
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_4
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_4
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{__name__="bla"} 3.14
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_5
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_5
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{label+="bla"} 3.14
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_6
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_6
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{label=bla} 3.14
|
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_7
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_7
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
# TYPE metric summary
|
||||||
|
metric{quantile="bla"} 3.14
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_8
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_8
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{label="bla"+} 3.14
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_9
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_9
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
metric{label="bla"} 3.14 2.72
|
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/minimal
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/prometheus/common/expfmt/fuzz/corpus/minimal
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
m{} 0
|
516
Godeps/_workspace/src/github.com/prometheus/common/expfmt/testdata/protobuf
generated
vendored
Normal file
516
Godeps/_workspace/src/github.com/prometheus/common/expfmt/testdata/protobuf
generated
vendored
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
fc08 0a22 6874 7470 5f72 6571 7565 7374
|
||||||
|
5f64 7572 6174 696f 6e5f 6d69 6372 6f73
|
||||||
|
6563 6f6e 6473 122b 5468 6520 4854 5450
|
||||||
|
2072 6571 7565 7374 206c 6174 656e 6369
|
||||||
|
6573 2069 6e20 6d69 6372 6f73 6563 6f6e
|
||||||
|
6473 2e18 0222 570a 0c0a 0768 616e 646c
|
||||||
|
6572 1201 2f22 4708 0011 0000 0000 0000
|
||||||
|
0000 1a12 0900 0000 0000 00e0 3f11 0000
|
||||||
|
0000 0000 0000 1a12 09cd cccc cccc ccec
|
||||||
|
3f11 0000 0000 0000 0000 1a12 09ae 47e1
|
||||||
|
7a14 aeef 3f11 0000 0000 0000 0000 225d
|
||||||
|
0a12 0a07 6861 6e64 6c65 7212 072f 616c
|
||||||
|
6572 7473 2247 0800 1100 0000 0000 0000
|
||||||
|
001a 1209 0000 0000 0000 e03f 1100 0000
|
||||||
|
0000 0000 001a 1209 cdcc cccc cccc ec3f
|
||||||
|
1100 0000 0000 0000 001a 1209 ae47 e17a
|
||||||
|
14ae ef3f 1100 0000 0000 0000 0022 620a
|
||||||
|
170a 0768 616e 646c 6572 120c 2f61 7069
|
||||||
|
2f6d 6574 7269 6373 2247 0800 1100 0000
|
||||||
|
0000 0000 001a 1209 0000 0000 0000 e03f
|
||||||
|
1100 0000 0000 0000 001a 1209 cdcc cccc
|
||||||
|
cccc ec3f 1100 0000 0000 0000 001a 1209
|
||||||
|
ae47 e17a 14ae ef3f 1100 0000 0000 0000
|
||||||
|
0022 600a 150a 0768 616e 646c 6572 120a
|
||||||
|
2f61 7069 2f71 7565 7279 2247 0800 1100
|
||||||
|
0000 0000 0000 001a 1209 0000 0000 0000
|
||||||
|
e03f 1100 0000 0000 0000 001a 1209 cdcc
|
||||||
|
cccc cccc ec3f 1100 0000 0000 0000 001a
|
||||||
|
1209 ae47 e17a 14ae ef3f 1100 0000 0000
|
||||||
|
0000 0022 660a 1b0a 0768 616e 646c 6572
|
||||||
|
1210 2f61 7069 2f71 7565 7279 5f72 616e
|
||||||
|
6765 2247 0800 1100 0000 0000 0000 001a
|
||||||
|
1209 0000 0000 0000 e03f 1100 0000 0000
|
||||||
|
0000 001a 1209 cdcc cccc cccc ec3f 1100
|
||||||
|
0000 0000 0000 001a 1209 ae47 e17a 14ae
|
||||||
|
ef3f 1100 0000 0000 0000 0022 620a 170a
|
||||||
|
0768 616e 646c 6572 120c 2f61 7069 2f74
|
||||||
|
6172 6765 7473 2247 0800 1100 0000 0000
|
||||||
|
0000 001a 1209 0000 0000 0000 e03f 1100
|
||||||
|
0000 0000 0000 001a 1209 cdcc cccc cccc
|
||||||
|
ec3f 1100 0000 0000 0000 001a 1209 ae47
|
||||||
|
e17a 14ae ef3f 1100 0000 0000 0000 0022
|
||||||
|
600a 150a 0768 616e 646c 6572 120a 2f63
|
||||||
|
6f6e 736f 6c65 732f 2247 0800 1100 0000
|
||||||
|
0000 0000 001a 1209 0000 0000 0000 e03f
|
||||||
|
1100 0000 0000 0000 001a 1209 cdcc cccc
|
||||||
|
cccc ec3f 1100 0000 0000 0000 001a 1209
|
||||||
|
ae47 e17a 14ae ef3f 1100 0000 0000 0000
|
||||||
|
0022 5c0a 110a 0768 616e 646c 6572 1206
|
||||||
|
2f67 7261 7068 2247 0800 1100 0000 0000
|
||||||
|
0000 001a 1209 0000 0000 0000 e03f 1100
|
||||||
|
0000 0000 0000 001a 1209 cdcc cccc cccc
|
||||||
|
ec3f 1100 0000 0000 0000 001a 1209 ae47
|
||||||
|
e17a 14ae ef3f 1100 0000 0000 0000 0022
|
||||||
|
5b0a 100a 0768 616e 646c 6572 1205 2f68
|
||||||
|
6561 7022 4708 0011 0000 0000 0000 0000
|
||||||
|
1a12 0900 0000 0000 00e0 3f11 0000 0000
|
||||||
|
0000 0000 1a12 09cd cccc cccc ccec 3f11
|
||||||
|
0000 0000 0000 0000 1a12 09ae 47e1 7a14
|
||||||
|
aeef 3f11 0000 0000 0000 0000 225e 0a13
|
||||||
|
0a07 6861 6e64 6c65 7212 082f 7374 6174
|
||||||
|
6963 2f22 4708 0011 0000 0000 0000 0000
|
||||||
|
1a12 0900 0000 0000 00e0 3f11 0000 0000
|
||||||
|
0000 0000 1a12 09cd cccc cccc ccec 3f11
|
||||||
|
0000 0000 0000 0000 1a12 09ae 47e1 7a14
|
||||||
|
aeef 3f11 0000 0000 0000 0000 2260 0a15
|
||||||
|
0a07 6861 6e64 6c65 7212 0a70 726f 6d65
|
||||||
|
7468 6575 7322 4708 3b11 5b8f c2f5 083f
|
||||||
|
f440 1a12 0900 0000 0000 00e0 3f11 e17a
|
||||||
|
14ae c7af 9340 1a12 09cd cccc cccc ccec
|
||||||
|
3f11 2fdd 2406 81f0 9640 1a12 09ae 47e1
|
||||||
|
7a14 aeef 3f11 3d0a d7a3 b095 a740 e608
|
||||||
|
0a17 6874 7470 5f72 6571 7565 7374 5f73
|
||||||
|
697a 655f 6279 7465 7312 2054 6865 2048
|
||||||
|
5454 5020 7265 7175 6573 7420 7369 7a65
|
||||||
|
7320 696e 2062 7974 6573 2e18 0222 570a
|
||||||
|
0c0a 0768 616e 646c 6572 1201 2f22 4708
|
||||||
|
0011 0000 0000 0000 0000 1a12 0900 0000
|
||||||
|
0000 00e0 3f11 0000 0000 0000 0000 1a12
|
||||||
|
09cd cccc cccc ccec 3f11 0000 0000 0000
|
||||||
|
0000 1a12 09ae 47e1 7a14 aeef 3f11 0000
|
||||||
|
0000 0000 0000 225d 0a12 0a07 6861 6e64
|
||||||
|
6c65 7212 072f 616c 6572 7473 2247 0800
|
||||||
|
1100 0000 0000 0000 001a 1209 0000 0000
|
||||||
|
0000 e03f 1100 0000 0000 0000 001a 1209
|
||||||
|
cdcc cccc cccc ec3f 1100 0000 0000 0000
|
||||||
|
001a 1209 ae47 e17a 14ae ef3f 1100 0000
|
||||||
|
0000 0000 0022 620a 170a 0768 616e 646c
|
||||||
|
6572 120c 2f61 7069 2f6d 6574 7269 6373
|
||||||
|
2247 0800 1100 0000 0000 0000 001a 1209
|
||||||
|
0000 0000 0000 e03f 1100 0000 0000 0000
|
||||||
|
001a 1209 cdcc cccc cccc ec3f 1100 0000
|
||||||
|
0000 0000 001a 1209 ae47 e17a 14ae ef3f
|
||||||
|
1100 0000 0000 0000 0022 600a 150a 0768
|
||||||
|
616e 646c 6572 120a 2f61 7069 2f71 7565
|
||||||
|
7279 2247 0800 1100 0000 0000 0000 001a
|
||||||
|
1209 0000 0000 0000 e03f 1100 0000 0000
|
||||||
|
0000 001a 1209 cdcc cccc cccc ec3f 1100
|
||||||
|
0000 0000 0000 001a 1209 ae47 e17a 14ae
|
||||||
|
ef3f 1100 0000 0000 0000 0022 660a 1b0a
|
||||||
|
0768 616e 646c 6572 1210 2f61 7069 2f71
|
||||||
|
7565 7279 5f72 616e 6765 2247 0800 1100
|
||||||
|
0000 0000 0000 001a 1209 0000 0000 0000
|
||||||
|
e03f 1100 0000 0000 0000 001a 1209 cdcc
|
||||||
|
cccc cccc ec3f 1100 0000 0000 0000 001a
|
||||||
|
1209 ae47 e17a 14ae ef3f 1100 0000 0000
|
||||||
|
0000 0022 620a 170a 0768 616e 646c 6572
|
||||||
|
120c 2f61 7069 2f74 6172 6765 7473 2247
|
||||||
|
0800 1100 0000 0000 0000 001a 1209 0000
|
||||||
|
0000 0000 e03f 1100 0000 0000 0000 001a
|
||||||
|
1209 cdcc cccc cccc ec3f 1100 0000 0000
|
||||||
|
0000 001a 1209 ae47 e17a 14ae ef3f 1100
|
||||||
|
0000 0000 0000 0022 600a 150a 0768 616e
|
||||||
|
646c 6572 120a 2f63 6f6e 736f 6c65 732f
|
||||||
|
2247 0800 1100 0000 0000 0000 001a 1209
|
||||||
|
0000 0000 0000 e03f 1100 0000 0000 0000
|
||||||
|
001a 1209 cdcc cccc cccc ec3f 1100 0000
|
||||||
|
0000 0000 001a 1209 ae47 e17a 14ae ef3f
|
||||||
|
1100 0000 0000 0000 0022 5c0a 110a 0768
|
||||||
|
616e 646c 6572 1206 2f67 7261 7068 2247
|
||||||
|
0800 1100 0000 0000 0000 001a 1209 0000
|
||||||
|
0000 0000 e03f 1100 0000 0000 0000 001a
|
||||||
|
1209 cdcc cccc cccc ec3f 1100 0000 0000
|
||||||
|
0000 001a 1209 ae47 e17a 14ae ef3f 1100
|
||||||
|
0000 0000 0000 0022 5b0a 100a 0768 616e
|
||||||
|
646c 6572 1205 2f68 6561 7022 4708 0011
|
||||||
|
0000 0000 0000 0000 1a12 0900 0000 0000
|
||||||
|
00e0 3f11 0000 0000 0000 0000 1a12 09cd
|
||||||
|
cccc cccc ccec 3f11 0000 0000 0000 0000
|
||||||
|
1a12 09ae 47e1 7a14 aeef 3f11 0000 0000
|
||||||
|
0000 0000 225e 0a13 0a07 6861 6e64 6c65
|
||||||
|
7212 082f 7374 6174 6963 2f22 4708 0011
|
||||||
|
0000 0000 0000 0000 1a12 0900 0000 0000
|
||||||
|
00e0 3f11 0000 0000 0000 0000 1a12 09cd
|
||||||
|
cccc cccc ccec 3f11 0000 0000 0000 0000
|
||||||
|
1a12 09ae 47e1 7a14 aeef 3f11 0000 0000
|
||||||
|
0000 0000 2260 0a15 0a07 6861 6e64 6c65
|
||||||
|
7212 0a70 726f 6d65 7468 6575 7322 4708
|
||||||
|
3b11 0000 0000 40c4 d040 1a12 0900 0000
|
||||||
|
0000 00e0 3f11 0000 0000 0030 7240 1a12
|
||||||
|
09cd cccc cccc ccec 3f11 0000 0000 0030
|
||||||
|
7240 1a12 09ae 47e1 7a14 aeef 3f11 0000
|
||||||
|
0000 0030 7240 7c0a 1368 7474 705f 7265
|
||||||
|
7175 6573 7473 5f74 6f74 616c 1223 546f
|
||||||
|
7461 6c20 6e75 6d62 6572 206f 6620 4854
|
||||||
|
5450 2072 6571 7565 7374 7320 6d61 6465
|
||||||
|
2e18 0022 3e0a 0b0a 0463 6f64 6512 0332
|
||||||
|
3030 0a15 0a07 6861 6e64 6c65 7212 0a70
|
||||||
|
726f 6d65 7468 6575 730a 0d0a 066d 6574
|
||||||
|
686f 6412 0367 6574 1a09 0900 0000 0000
|
||||||
|
804d 40e8 080a 1868 7474 705f 7265 7370
|
||||||
|
6f6e 7365 5f73 697a 655f 6279 7465 7312
|
||||||
|
2154 6865 2048 5454 5020 7265 7370 6f6e
|
||||||
|
7365 2073 697a 6573 2069 6e20 6279 7465
|
||||||
|
732e 1802 2257 0a0c 0a07 6861 6e64 6c65
|
||||||
|
7212 012f 2247 0800 1100 0000 0000 0000
|
||||||
|
001a 1209 0000 0000 0000 e03f 1100 0000
|
||||||
|
0000 0000 001a 1209 cdcc cccc cccc ec3f
|
||||||
|
1100 0000 0000 0000 001a 1209 ae47 e17a
|
||||||
|
14ae ef3f 1100 0000 0000 0000 0022 5d0a
|
||||||
|
120a 0768 616e 646c 6572 1207 2f61 6c65
|
||||||
|
7274 7322 4708 0011 0000 0000 0000 0000
|
||||||
|
1a12 0900 0000 0000 00e0 3f11 0000 0000
|
||||||
|
0000 0000 1a12 09cd cccc cccc ccec 3f11
|
||||||
|
0000 0000 0000 0000 1a12 09ae 47e1 7a14
|
||||||
|
aeef 3f11 0000 0000 0000 0000 2262 0a17
|
||||||
|
0a07 6861 6e64 6c65 7212 0c2f 6170 692f
|
||||||
|
6d65 7472 6963 7322 4708 0011 0000 0000
|
||||||
|
0000 0000 1a12 0900 0000 0000 00e0 3f11
|
||||||
|
0000 0000 0000 0000 1a12 09cd cccc cccc
|
||||||
|
ccec 3f11 0000 0000 0000 0000 1a12 09ae
|
||||||
|
47e1 7a14 aeef 3f11 0000 0000 0000 0000
|
||||||
|
2260 0a15 0a07 6861 6e64 6c65 7212 0a2f
|
||||||
|
6170 692f 7175 6572 7922 4708 0011 0000
|
||||||
|
0000 0000 0000 1a12 0900 0000 0000 00e0
|
||||||
|
3f11 0000 0000 0000 0000 1a12 09cd cccc
|
||||||
|
cccc ccec 3f11 0000 0000 0000 0000 1a12
|
||||||
|
09ae 47e1 7a14 aeef 3f11 0000 0000 0000
|
||||||
|
0000 2266 0a1b 0a07 6861 6e64 6c65 7212
|
||||||
|
102f 6170 692f 7175 6572 795f 7261 6e67
|
||||||
|
6522 4708 0011 0000 0000 0000 0000 1a12
|
||||||
|
0900 0000 0000 00e0 3f11 0000 0000 0000
|
||||||
|
0000 1a12 09cd cccc cccc ccec 3f11 0000
|
||||||
|
0000 0000 0000 1a12 09ae 47e1 7a14 aeef
|
||||||
|
3f11 0000 0000 0000 0000 2262 0a17 0a07
|
||||||
|
6861 6e64 6c65 7212 0c2f 6170 692f 7461
|
||||||
|
7267 6574 7322 4708 0011 0000 0000 0000
|
||||||
|
0000 1a12 0900 0000 0000 00e0 3f11 0000
|
||||||
|
0000 0000 0000 1a12 09cd cccc cccc ccec
|
||||||
|
3f11 0000 0000 0000 0000 1a12 09ae 47e1
|
||||||
|
7a14 aeef 3f11 0000 0000 0000 0000 2260
|
||||||
|
0a15 0a07 6861 6e64 6c65 7212 0a2f 636f
|
||||||
|
6e73 6f6c 6573 2f22 4708 0011 0000 0000
|
||||||
|
0000 0000 1a12 0900 0000 0000 00e0 3f11
|
||||||
|
0000 0000 0000 0000 1a12 09cd cccc cccc
|
||||||
|
ccec 3f11 0000 0000 0000 0000 1a12 09ae
|
||||||
|
47e1 7a14 aeef 3f11 0000 0000 0000 0000
|
||||||
|
225c 0a11 0a07 6861 6e64 6c65 7212 062f
|
||||||
|
6772 6170 6822 4708 0011 0000 0000 0000
|
||||||
|
0000 1a12 0900 0000 0000 00e0 3f11 0000
|
||||||
|
0000 0000 0000 1a12 09cd cccc cccc ccec
|
||||||
|
3f11 0000 0000 0000 0000 1a12 09ae 47e1
|
||||||
|
7a14 aeef 3f11 0000 0000 0000 0000 225b
|
||||||
|
0a10 0a07 6861 6e64 6c65 7212 052f 6865
|
||||||
|
6170 2247 0800 1100 0000 0000 0000 001a
|
||||||
|
1209 0000 0000 0000 e03f 1100 0000 0000
|
||||||
|
0000 001a 1209 cdcc cccc cccc ec3f 1100
|
||||||
|
0000 0000 0000 001a 1209 ae47 e17a 14ae
|
||||||
|
ef3f 1100 0000 0000 0000 0022 5e0a 130a
|
||||||
|
0768 616e 646c 6572 1208 2f73 7461 7469
|
||||||
|
632f 2247 0800 1100 0000 0000 0000 001a
|
||||||
|
1209 0000 0000 0000 e03f 1100 0000 0000
|
||||||
|
0000 001a 1209 cdcc cccc cccc ec3f 1100
|
||||||
|
0000 0000 0000 001a 1209 ae47 e17a 14ae
|
||||||
|
ef3f 1100 0000 0000 0000 0022 600a 150a
|
||||||
|
0768 616e 646c 6572 120a 7072 6f6d 6574
|
||||||
|
6865 7573 2247 083b 1100 0000 00e0 b4fc
|
||||||
|
401a 1209 0000 0000 0000 e03f 1100 0000
|
||||||
|
0000 349f 401a 1209 cdcc cccc cccc ec3f
|
||||||
|
1100 0000 0000 08a0 401a 1209 ae47 e17a
|
||||||
|
14ae ef3f 1100 0000 0000 0aa0 405c 0a19
|
||||||
|
7072 6f63 6573 735f 6370 755f 7365 636f
|
||||||
|
6e64 735f 746f 7461 6c12 3054 6f74 616c
|
||||||
|
2075 7365 7220 616e 6420 7379 7374 656d
|
||||||
|
2043 5055 2074 696d 6520 7370 656e 7420
|
||||||
|
696e 2073 6563 6f6e 6473 2e18 0022 0b1a
|
||||||
|
0909 a470 3d0a d7a3 d03f 4f0a 1270 726f
|
||||||
|
6365 7373 5f67 6f72 6f75 7469 6e65 7312
|
||||||
|
2a4e 756d 6265 7220 6f66 2067 6f72 6f75
|
||||||
|
7469 6e65 7320 7468 6174 2063 7572 7265
|
||||||
|
6e74 6c79 2065 7869 7374 2e18 0122 0b12
|
||||||
|
0909 0000 0000 0000 5140 4a0a 0f70 726f
|
||||||
|
6365 7373 5f6d 6178 5f66 6473 1228 4d61
|
||||||
|
7869 6d75 6d20 6e75 6d62 6572 206f 6620
|
||||||
|
6f70 656e 2066 696c 6520 6465 7363 7269
|
||||||
|
7074 6f72 732e 1801 220b 1209 0900 0000
|
||||||
|
0000 00c0 4043 0a10 7072 6f63 6573 735f
|
||||||
|
6f70 656e 5f66 6473 1220 4e75 6d62 6572
|
||||||
|
206f 6620 6f70 656e 2066 696c 6520 6465
|
||||||
|
7363 7269 7074 6f72 732e 1801 220b 1209
|
||||||
|
0900 0000 0000 003d 404e 0a1d 7072 6f63
|
||||||
|
6573 735f 7265 7369 6465 6e74 5f6d 656d
|
||||||
|
6f72 795f 6279 7465 7312 1e52 6573 6964
|
||||||
|
656e 7420 6d65 6d6f 7279 2073 697a 6520
|
||||||
|
696e 2062 7974 6573 2e18 0122 0b12 0909
|
||||||
|
0000 0000 004b 8841 630a 1a70 726f 6365
|
||||||
|
7373 5f73 7461 7274 5f74 696d 655f 7365
|
||||||
|
636f 6e64 7312 3653 7461 7274 2074 696d
|
||||||
|
6520 6f66 2074 6865 2070 726f 6365 7373
|
||||||
|
2073 696e 6365 2075 6e69 7820 6570 6f63
|
||||||
|
6820 696e 2073 6563 6f6e 6473 2e18 0122
|
||||||
|
0b12 0909 3d0a 172d e831 d541 4c0a 1c70
|
||||||
|
726f 6365 7373 5f76 6972 7475 616c 5f6d
|
||||||
|
656d 6f72 795f 6279 7465 7312 1d56 6972
|
||||||
|
7475 616c 206d 656d 6f72 7920 7369 7a65
|
||||||
|
2069 6e20 6279 7465 732e 1801 220b 1209
|
||||||
|
0900 0000 0020 12c0 415f 0a27 7072 6f6d
|
||||||
|
6574 6865 7573 5f64 6e73 5f73 645f 6c6f
|
||||||
|
6f6b 7570 5f66 6169 6c75 7265 735f 746f
|
||||||
|
7461 6c12 2554 6865 206e 756d 6265 7220
|
||||||
|
6f66 2044 4e53 2d53 4420 6c6f 6f6b 7570
|
||||||
|
2066 6169 6c75 7265 732e 1800 220b 1a09
|
||||||
|
0900 0000 0000 0000 004f 0a1f 7072 6f6d
|
||||||
|
6574 6865 7573 5f64 6e73 5f73 645f 6c6f
|
||||||
|
6f6b 7570 735f 746f 7461 6c12 1d54 6865
|
||||||
|
206e 756d 6265 7220 6f66 2044 4e53 2d53
|
||||||
|
4420 6c6f 6f6b 7570 732e 1800 220b 1a09
|
||||||
|
0900 0000 0000 0008 40cf 010a 2a70 726f
|
||||||
|
6d65 7468 6575 735f 6576 616c 7561 746f
|
||||||
|
725f 6475 7261 7469 6f6e 5f6d 696c 6c69
|
||||||
|
7365 636f 6e64 7312 2c54 6865 2064 7572
|
||||||
|
6174 696f 6e20 666f 7220 616c 6c20 6576
|
||||||
|
616c 7561 7469 6f6e 7320 746f 2065 7865
|
||||||
|
6375 7465 2e18 0222 7122 6f08 0b11 0000
|
||||||
|
0000 0000 2240 1a12 097b 14ae 47e1 7a84
|
||||||
|
3f11 0000 0000 0000 0000 1a12 099a 9999
|
||||||
|
9999 99a9 3f11 0000 0000 0000 0000 1a12
|
||||||
|
0900 0000 0000 00e0 3f11 0000 0000 0000
|
||||||
|
0000 1a12 09cd cccc cccc ccec 3f11 0000
|
||||||
|
0000 0000 f03f 1a12 09ae 47e1 7a14 aeef
|
||||||
|
3f11 0000 0000 0000 f03f a301 0a39 7072
|
||||||
|
6f6d 6574 6865 7573 5f6c 6f63 616c 5f73
|
||||||
|
746f 7261 6765 5f63 6865 636b 706f 696e
|
||||||
|
745f 6475 7261 7469 6f6e 5f6d 696c 6c69
|
||||||
|
7365 636f 6e64 7312 5754 6865 2064 7572
|
||||||
|
6174 696f 6e20 2869 6e20 6d69 6c6c 6973
|
||||||
|
6563 6f6e 6473 2920 6974 2074 6f6f 6b20
|
||||||
|
746f 2063 6865 636b 706f 696e 7420 696e
|
||||||
|
2d6d 656d 6f72 7920 6d65 7472 6963 7320
|
||||||
|
616e 6420 6865 6164 2063 6875 6e6b 732e
|
||||||
|
1801 220b 1209 0900 0000 0000 0000 00f2
|
||||||
|
010a 2870 726f 6d65 7468 6575 735f 6c6f
|
||||||
|
6361 6c5f 7374 6f72 6167 655f 6368 756e
|
||||||
|
6b5f 6f70 735f 746f 7461 6c12 3354 6865
|
||||||
|
2074 6f74 616c 206e 756d 6265 7220 6f66
|
||||||
|
2063 6875 6e6b 206f 7065 7261 7469 6f6e
|
||||||
|
7320 6279 2074 6865 6972 2074 7970 652e
|
||||||
|
1800 221b 0a0e 0a04 7479 7065 1206 6372
|
||||||
|
6561 7465 1a09 0900 0000 0000 b880 4022
|
||||||
|
1c0a 0f0a 0474 7970 6512 0770 6572 7369
|
||||||
|
7374 1a09 0900 0000 0000 c05b 4022 180a
|
||||||
|
0b0a 0474 7970 6512 0370 696e 1a09 0900
|
||||||
|
0000 0000 807b 4022 1e0a 110a 0474 7970
|
||||||
|
6512 0974 7261 6e73 636f 6465 1a09 0900
|
||||||
|
0000 0000 a06b 4022 1a0a 0d0a 0474 7970
|
||||||
|
6512 0575 6e70 696e 1a09 0900 0000 0000
|
||||||
|
807b 40c4 010a 3c70 726f 6d65 7468 6575
|
||||||
|
735f 6c6f 6361 6c5f 7374 6f72 6167 655f
|
||||||
|
696e 6465 7869 6e67 5f62 6174 6368 5f6c
|
||||||
|
6174 656e 6379 5f6d 696c 6c69 7365 636f
|
||||||
|
6e64 7312 3751 7561 6e74 696c 6573 2066
|
||||||
|
6f72 2062 6174 6368 2069 6e64 6578 696e
|
||||||
|
6720 6c61 7465 6e63 6965 7320 696e 206d
|
||||||
|
696c 6c69 7365 636f 6e64 732e 1802 2249
|
||||||
|
2247 0801 1100 0000 0000 0000 001a 1209
|
||||||
|
0000 0000 0000 e03f 1100 0000 0000 0000
|
||||||
|
001a 1209 cdcc cccc cccc ec3f 1100 0000
|
||||||
|
0000 0000 001a 1209 ae47 e17a 14ae ef3f
|
||||||
|
1100 0000 0000 0000 00bf 010a 2d70 726f
|
||||||
|
6d65 7468 6575 735f 6c6f 6361 6c5f 7374
|
||||||
|
6f72 6167 655f 696e 6465 7869 6e67 5f62
|
||||||
|
6174 6368 5f73 697a 6573 1241 5175 616e
|
||||||
|
7469 6c65 7320 666f 7220 696e 6465 7869
|
||||||
|
6e67 2062 6174 6368 2073 697a 6573 2028
|
||||||
|
6e75 6d62 6572 206f 6620 6d65 7472 6963
|
||||||
|
7320 7065 7220 6261 7463 6829 2e18 0222
|
||||||
|
4922 4708 0111 0000 0000 0000 0040 1a12
|
||||||
|
0900 0000 0000 00e0 3f11 0000 0000 0000
|
||||||
|
0040 1a12 09cd cccc cccc ccec 3f11 0000
|
||||||
|
0000 0000 0040 1a12 09ae 47e1 7a14 aeef
|
||||||
|
3f11 0000 0000 0000 0040 660a 3070 726f
|
||||||
|
6d65 7468 6575 735f 6c6f 6361 6c5f 7374
|
||||||
|
6f72 6167 655f 696e 6465 7869 6e67 5f71
|
||||||
|
7565 7565 5f63 6170 6163 6974 7912 2354
|
||||||
|
6865 2063 6170 6163 6974 7920 6f66 2074
|
||||||
|
6865 2069 6e64 6578 696e 6720 7175 6575
|
||||||
|
652e 1801 220b 1209 0900 0000 0000 00d0
|
||||||
|
406d 0a2e 7072 6f6d 6574 6865 7573 5f6c
|
||||||
|
6f63 616c 5f73 746f 7261 6765 5f69 6e64
|
||||||
|
6578 696e 675f 7175 6575 655f 6c65 6e67
|
||||||
|
7468 122c 5468 6520 6e75 6d62 6572 206f
|
||||||
|
6620 6d65 7472 6963 7320 7761 6974 696e
|
||||||
|
6720 746f 2062 6520 696e 6465 7865 642e
|
||||||
|
1801 220b 1209 0900 0000 0000 0000 0067
|
||||||
|
0a2f 7072 6f6d 6574 6865 7573 5f6c 6f63
|
||||||
|
616c 5f73 746f 7261 6765 5f69 6e67 6573
|
||||||
|
7465 645f 7361 6d70 6c65 735f 746f 7461
|
||||||
|
6c12 2554 6865 2074 6f74 616c 206e 756d
|
||||||
|
6265 7220 6f66 2073 616d 706c 6573 2069
|
||||||
|
6e67 6573 7465 642e 1800 220b 1a09 0900
|
||||||
|
0000 0080 27cd 40c3 010a 3770 726f 6d65
|
||||||
|
7468 6575 735f 6c6f 6361 6c5f 7374 6f72
|
||||||
|
6167 655f 696e 7661 6c69 645f 7072 656c
|
||||||
|
6f61 645f 7265 7175 6573 7473 5f74 6f74
|
||||||
|
616c 1279 5468 6520 746f 7461 6c20 6e75
|
||||||
|
6d62 6572 206f 6620 7072 656c 6f61 6420
|
||||||
|
7265 7175 6573 7473 2072 6566 6572 7269
|
||||||
|
6e67 2074 6f20 6120 6e6f 6e2d 6578 6973
|
||||||
|
7465 6e74 2073 6572 6965 732e 2054 6869
|
||||||
|
7320 6973 2061 6e20 696e 6469 6361 7469
|
||||||
|
6f6e 206f 6620 6f75 7464 6174 6564 206c
|
||||||
|
6162 656c 2069 6e64 6578 6573 2e18 0022
|
||||||
|
0b1a 0909 0000 0000 0000 0000 6f0a 2a70
|
||||||
|
726f 6d65 7468 6575 735f 6c6f 6361 6c5f
|
||||||
|
7374 6f72 6167 655f 6d65 6d6f 7279 5f63
|
||||||
|
6875 6e6b 6465 7363 7312 3254 6865 2063
|
||||||
|
7572 7265 6e74 206e 756d 6265 7220 6f66
|
||||||
|
2063 6875 6e6b 2064 6573 6372 6970 746f
|
||||||
|
7273 2069 6e20 6d65 6d6f 7279 2e18 0122
|
||||||
|
0b12 0909 0000 0000 0020 8f40 9c01 0a26
|
||||||
|
7072 6f6d 6574 6865 7573 5f6c 6f63 616c
|
||||||
|
5f73 746f 7261 6765 5f6d 656d 6f72 795f
|
||||||
|
6368 756e 6b73 1263 5468 6520 6375 7272
|
||||||
|
656e 7420 6e75 6d62 6572 206f 6620 6368
|
||||||
|
756e 6b73 2069 6e20 6d65 6d6f 7279 2c20
|
||||||
|
6578 636c 7564 696e 6720 636c 6f6e 6564
|
||||||
|
2063 6875 6e6b 7320 2869 2e65 2e20 6368
|
||||||
|
756e 6b73 2077 6974 686f 7574 2061 2064
|
||||||
|
6573 6372 6970 746f 7229 2e18 0122 0b12
|
||||||
|
0909 0000 0000 00e8 8d40 600a 2670 726f
|
||||||
|
6d65 7468 6575 735f 6c6f 6361 6c5f 7374
|
||||||
|
6f72 6167 655f 6d65 6d6f 7279 5f73 6572
|
||||||
|
6965 7312 2754 6865 2063 7572 7265 6e74
|
||||||
|
206e 756d 6265 7220 6f66 2073 6572 6965
|
||||||
|
7320 696e 206d 656d 6f72 792e 1801 220b
|
||||||
|
1209 0900 0000 0000 807a 40b7 010a 3570
|
||||||
|
726f 6d65 7468 6575 735f 6c6f 6361 6c5f
|
||||||
|
7374 6f72 6167 655f 7065 7273 6973 745f
|
||||||
|
6c61 7465 6e63 795f 6d69 6372 6f73 6563
|
||||||
|
6f6e 6473 1231 4120 7375 6d6d 6172 7920
|
||||||
|
6f66 206c 6174 656e 6369 6573 2066 6f72
|
||||||
|
2070 6572 7369 7374 696e 6720 6561 6368
|
||||||
|
2063 6875 6e6b 2e18 0222 4922 4708 6f11
|
||||||
|
1c2f dd24 e68c cc40 1a12 0900 0000 0000
|
||||||
|
00e0 3f11 8d97 6e12 8360 3e40 1a12 09cd
|
||||||
|
cccc cccc ccec 3f11 0ad7 a370 3d62 6b40
|
||||||
|
1a12 09ae 47e1 7a14 aeef 3f11 7b14 ae47
|
||||||
|
e1b6 7240 6a0a 2f70 726f 6d65 7468 6575
|
||||||
|
735f 6c6f 6361 6c5f 7374 6f72 6167 655f
|
||||||
|
7065 7273 6973 745f 7175 6575 655f 6361
|
||||||
|
7061 6369 7479 1228 5468 6520 746f 7461
|
||||||
|
6c20 6361 7061 6369 7479 206f 6620 7468
|
||||||
|
6520 7065 7273 6973 7420 7175 6575 652e
|
||||||
|
1801 220b 1209 0900 0000 0000 0090 407a
|
||||||
|
0a2d 7072 6f6d 6574 6865 7573 5f6c 6f63
|
||||||
|
616c 5f73 746f 7261 6765 5f70 6572 7369
|
||||||
|
7374 5f71 7565 7565 5f6c 656e 6774 6812
|
||||||
|
3a54 6865 2063 7572 7265 6e74 206e 756d
|
||||||
|
6265 7220 6f66 2063 6875 6e6b 7320 7761
|
||||||
|
6974 696e 6720 696e 2074 6865 2070 6572
|
||||||
|
7369 7374 2071 7565 7565 2e18 0122 0b12
|
||||||
|
0909 0000 0000 0000 0000 ac01 0a29 7072
|
||||||
|
6f6d 6574 6865 7573 5f6c 6f63 616c 5f73
|
||||||
|
746f 7261 6765 5f73 6572 6965 735f 6f70
|
||||||
|
735f 746f 7461 6c12 3454 6865 2074 6f74
|
||||||
|
616c 206e 756d 6265 7220 6f66 2073 6572
|
||||||
|
6965 7320 6f70 6572 6174 696f 6e73 2062
|
||||||
|
7920 7468 6569 7220 7479 7065 2e18 0022
|
||||||
|
1b0a 0e0a 0474 7970 6512 0663 7265 6174
|
||||||
|
651a 0909 0000 0000 0000 0040 222a 0a1d
|
||||||
|
0a04 7479 7065 1215 6d61 696e 7465 6e61
|
||||||
|
6e63 655f 696e 5f6d 656d 6f72 791a 0909
|
||||||
|
0000 0000 0000 1440 d601 0a2d 7072 6f6d
|
||||||
|
6574 6865 7573 5f6e 6f74 6966 6963 6174
|
||||||
|
696f 6e73 5f6c 6174 656e 6379 5f6d 696c
|
||||||
|
6c69 7365 636f 6e64 7312 584c 6174 656e
|
||||||
|
6379 2071 7561 6e74 696c 6573 2066 6f72
|
||||||
|
2073 656e 6469 6e67 2061 6c65 7274 206e
|
||||||
|
6f74 6966 6963 6174 696f 6e73 2028 6e6f
|
||||||
|
7420 696e 636c 7564 696e 6720 6472 6f70
|
||||||
|
7065 6420 6e6f 7469 6669 6361 7469 6f6e
|
||||||
|
7329 2e18 0222 4922 4708 0011 0000 0000
|
||||||
|
0000 0000 1a12 0900 0000 0000 00e0 3f11
|
||||||
|
0000 0000 0000 0000 1a12 09cd cccc cccc
|
||||||
|
ccec 3f11 0000 0000 0000 0000 1a12 09ae
|
||||||
|
47e1 7a14 aeef 3f11 0000 0000 0000 0000
|
||||||
|
680a 2770 726f 6d65 7468 6575 735f 6e6f
|
||||||
|
7469 6669 6361 7469 6f6e 735f 7175 6575
|
||||||
|
655f 6361 7061 6369 7479 122e 5468 6520
|
||||||
|
6361 7061 6369 7479 206f 6620 7468 6520
|
||||||
|
616c 6572 7420 6e6f 7469 6669 6361 7469
|
||||||
|
6f6e 7320 7175 6575 652e 1801 220b 1209
|
||||||
|
0900 0000 0000 0059 4067 0a25 7072 6f6d
|
||||||
|
6574 6865 7573 5f6e 6f74 6966 6963 6174
|
||||||
|
696f 6e73 5f71 7565 7565 5f6c 656e 6774
|
||||||
|
6812 2f54 6865 206e 756d 6265 7220 6f66
|
||||||
|
2061 6c65 7274 206e 6f74 6966 6963 6174
|
||||||
|
696f 6e73 2069 6e20 7468 6520 7175 6575
|
||||||
|
652e 1801 220b 1209 0900 0000 0000 0000
|
||||||
|
009e 020a 3070 726f 6d65 7468 6575 735f
|
||||||
|
7275 6c65 5f65 7661 6c75 6174 696f 6e5f
|
||||||
|
6475 7261 7469 6f6e 5f6d 696c 6c69 7365
|
||||||
|
636f 6e64 7312 2354 6865 2064 7572 6174
|
||||||
|
696f 6e20 666f 7220 6120 7275 6c65 2074
|
||||||
|
6f20 6578 6563 7574 652e 1802 2260 0a15
|
||||||
|
0a09 7275 6c65 5f74 7970 6512 0861 6c65
|
||||||
|
7274 696e 6722 4708 3711 0000 0000 0000
|
||||||
|
2840 1a12 0900 0000 0000 00e0 3f11 0000
|
||||||
|
0000 0000 0000 1a12 09cd cccc cccc ccec
|
||||||
|
3f11 0000 0000 0000 0000 1a12 09ae 47e1
|
||||||
|
7a14 aeef 3f11 0000 0000 0000 0840 2261
|
||||||
|
0a16 0a09 7275 6c65 5f74 7970 6512 0972
|
||||||
|
6563 6f72 6469 6e67 2247 0837 1100 0000
|
||||||
|
0000 002e 401a 1209 0000 0000 0000 e03f
|
||||||
|
1100 0000 0000 0000 001a 1209 cdcc cccc
|
||||||
|
cccc ec3f 1100 0000 0000 0000 001a 1209
|
||||||
|
ae47 e17a 14ae ef3f 1100 0000 0000 0008
|
||||||
|
4069 0a29 7072 6f6d 6574 6865 7573 5f72
|
||||||
|
756c 655f 6576 616c 7561 7469 6f6e 5f66
|
||||||
|
6169 6c75 7265 735f 746f 7461 6c12 2d54
|
||||||
|
6865 2074 6f74 616c 206e 756d 6265 7220
|
||||||
|
6f66 2072 756c 6520 6576 616c 7561 7469
|
||||||
|
6f6e 2066 6169 6c75 7265 732e 1800 220b
|
||||||
|
1a09 0900 0000 0000 0000 0060 0a21 7072
|
||||||
|
6f6d 6574 6865 7573 5f73 616d 706c 6573
|
||||||
|
5f71 7565 7565 5f63 6170 6163 6974 7912
|
||||||
|
2c43 6170 6163 6974 7920 6f66 2074 6865
|
||||||
|
2071 7565 7565 2066 6f72 2075 6e77 7269
|
||||||
|
7474 656e 2073 616d 706c 6573 2e18 0122
|
||||||
|
0b12 0909 0000 0000 0000 b040 da01 0a1f
|
||||||
|
7072 6f6d 6574 6865 7573 5f73 616d 706c
|
||||||
|
6573 5f71 7565 7565 5f6c 656e 6774 6812
|
||||||
|
a701 4375 7272 656e 7420 6e75 6d62 6572
|
||||||
|
206f 6620 6974 656d 7320 696e 2074 6865
|
||||||
|
2071 7565 7565 2066 6f72 2075 6e77 7269
|
||||||
|
7474 656e 2073 616d 706c 6573 2e20 4561
|
||||||
|
6368 2069 7465 6d20 636f 6d70 7269 7365
|
||||||
|
7320 616c 6c20 7361 6d70 6c65 7320 6578
|
||||||
|
706f 7365 6420 6279 206f 6e65 2074 6172
|
||||||
|
6765 7420 6173 206f 6e65 206d 6574 7269
|
||||||
|
6320 6661 6d69 6c79 2028 692e 652e 206d
|
||||||
|
6574 7269 6373 206f 6620 7468 6520 7361
|
||||||
|
6d65 206e 616d 6529 2e18 0122 0b12 0909
|
||||||
|
0000 0000 0000 0000 d902 0a29 7072 6f6d
|
||||||
|
6574 6865 7573 5f74 6172 6765 745f 696e
|
||||||
|
7465 7276 616c 5f6c 656e 6774 685f 7365
|
||||||
|
636f 6e64 7312 2141 6374 7561 6c20 696e
|
||||||
|
7465 7276 616c 7320 6265 7477 6565 6e20
|
||||||
|
7363 7261 7065 732e 1802 2282 010a 0f0a
|
||||||
|
0869 6e74 6572 7661 6c12 0331 3573 226f
|
||||||
|
0804 1100 0000 0000 804d 401a 1209 7b14
|
||||||
|
ae47 e17a 843f 1100 0000 0000 002c 401a
|
||||||
|
1209 9a99 9999 9999 a93f 1100 0000 0000
|
||||||
|
002c 401a 1209 0000 0000 0000 e03f 1100
|
||||||
|
0000 0000 002e 401a 1209 cdcc cccc cccc
|
||||||
|
ec3f 1100 0000 0000 002e 401a 1209 ae47
|
||||||
|
e17a 14ae ef3f 1100 0000 0000 002e 4022
|
||||||
|
8101 0a0e 0a08 696e 7465 7276 616c 1202
|
||||||
|
3173 226f 083a 1100 0000 0000 003c 401a
|
||||||
|
1209 7b14 ae47 e17a 843f 1100 0000 0000
|
||||||
|
0000 001a 1209 9a99 9999 9999 a93f 1100
|
||||||
|
0000 0000 0000 001a 1209 0000 0000 0000
|
||||||
|
e03f 1100 0000 0000 0000 001a 1209 cdcc
|
||||||
|
cccc cccc ec3f 1100 0000 0000 00f0 3f1a
|
||||||
|
1209 ae47 e17a 14ae ef3f 1100 0000 0000
|
||||||
|
00f0 3f
|
129
Godeps/_workspace/src/github.com/prometheus/common/expfmt/testdata/protobuf.gz
generated
vendored
Normal file
129
Godeps/_workspace/src/github.com/prometheus/common/expfmt/testdata/protobuf.gz
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
1f8b 0808 efa0 c754 0003 7072 6f74 6f62
|
||||||
|
7566 00ed 594d 8c1c c515 9eb1 8d3d 5b86
|
||||||
|
6037 265e 8c4d ca03 c4bb ceee cc9a 9f58
|
||||||
|
01cc f6ca 4424 041b 8837 21c8 24ed daee
|
||||||
|
9a99 cef6 1f55 d578 c7e4 b004 0e39 8088
|
||||||
|
8448 048a 124b 4442 9110 e110 25b9 c54a
|
||||||
|
9072 01c5 9724 4a24 2472 413e 448a 8592
|
||||||
|
1b87 bcea aeda eeea 99d9 3530 49a4 68e7
|
||||||
|
b0bb 5355 fdde abf7 bef7 bdf7 7a3f 6ca0
|
||||||
|
664f 88c4 61f4 8994 72e1 7829 23c2 8f23
|
||||||
|
27f4 5d16 73ea c691 c7ad cf2d f628 fed2
|
||||||
|
e2e2 c358 9dc3 0111 3472 7dca b11f e1f2
|
||||||
|
d9d6 e496 e6a3 e86a b4a3 4722 2fa0 ccaa
|
||||||
|
b79b f737 6abb 6bea b3cf 9ac8 ff78 6fbe
|
||||||
|
bcf6 cedb f2f3 7763 ed8d fbff 766e cf1b
|
||||||
|
ff28 d69a df44 5621 7847 9bc0 2fc1 c727
|
||||||
|
7e09 ed2d c45f dd26 89df 0ea9 60be 3b46
|
||||||
|
1d67 d0f5 850e 94e9 008f b2fe f834 74d0
|
||||||
|
8d85 865d 8506 8791 a84b ffa3 de12 8475
|
||||||
|
e938 2352 f116 208c c701 e563 84d4 e368
|
||||||
|
77a1 617b bbcb 48d2 1b9f f4d3 6857 21fd
|
||||||
|
aa76 8f92 647c c2bf 85ae 2b84 37da 5c40
|
||||||
|
e6ba 6374 8de9 fc84 c590 0c3d 9aca f0de
|
||||||
|
bdfb f40b bffd 5763 fe9f 7659 8314 f0fb
|
||||||
|
9fbf 6897 35b4 dfbd 65fb d397 7f60 9735
|
||||||
|
1c43 7f7e f5cd 975e b3df 6fa0 bd06 fb70
|
||||||
|
ff1c 7596 fa82 720b 0f50 8edc cce8 263b
|
||||||
|
b0c9 339b 3cb3 c933 5afa ff2f cfc8 13f6
|
||||||
|
5b17 ed01 0d73 cc1e d090 af99 1a60 ed3b
|
||||||
|
e8ba 32cd 7047 c482 04d6 cd8b f217 8ed2
|
||||||
|
7089 321c 770c bae1 3824 1e6d 4dd6 9af7
|
||||||
|
a29d 689b 1b7b d4da 7adb dcdc 085b d135
|
||||||
|
68bb fc33 f6ac ad00 cd7d 13b9 b5ab 27ec
|
||||||
|
4b0d 34a9 b4f3 0470 45cb 2c77 b0c4 72f9
|
||||||
|
ee26 cd7d 02ec 6cd2 dc26 cd7d 6ce1 ff73
|
||||||
|
9a7b ef17 1f0e d2dc 1d3f 19a4 b9c6 f941
|
||||||
|
9a43 e7ed c7d1 0d20 d5a5 9c3b 6e92 3a6a
|
||||||
|
2053 6437 9793 5dca 81ea c006 ccfb 5cd0
|
||||||
|
101f 7ff8 6b58 f821 d04e 4223 2169 676d
|
||||||
|
8eab 3577 028d fd34 91dd dac5 f987 90a5
|
||||||
|
8577 6316 a7c2 8f80 bf0e 9f5c 23cf 6215
|
||||||
|
8b1e 11d8 4d19 0391 411f d315 9f8b d664
|
||||||
|
bdb9 d352 b458 7bc4 7e00 5dab e585 64c5
|
||||||
|
e9c0 9439 7582 acf8 611a 9618 3906 ab70
|
||||||
|
c70f 28f6 2877 999f 8898 7153 d405 fb38
|
||||||
|
daa5 45c9 f399 2c7c f2a3 c838 669f 4407
|
||||||
|
b40c 6062 df03 cb9d 9086 31e4 79ce d437
|
||||||
|
7d55 2de3 7c39 e3e9 124d 97c4 7de5 7b0b
|
||||||
|
2eda a7c5 018e 9870 a48f 7544 accf 9f92
|
||||||
|
6bb9 dfc1 4040 0156 a741 6ae4 529c 46fe
|
||||||
|
0aa6 49ec f68c 88e4 3a8e a1bd b397 8efc
|
||||||
|
71e1 41b4 5feb 78d2 6722 2581 69f1 81af
|
||||||
|
e7ab 1b1a 8cad 0b0b 0e3a 5420 d2f1 22b0
|
||||||
|
db73 8238 5e4e 13a7 43fc 2005 af28 24dd
|
||||||
|
2a6b 5611 a2fb 4e9e 9a3d 751f cecf 627d
|
||||||
|
56c3 47a3 ff21 f499 51f2 b5dc 03eb c8ad
|
||||||
|
c86b d87f a8a3 c325 81f4 4912 a404 025b
|
||||||
|
7e81 1104 bef6 f88c 94ad b770 2786 1c08
|
||||||
|
02ac 9e82 25c0 6c0c 38a5 6e2a a82c b94f
|
||||||
|
34e3 c64e 95ba 4d99 6c4f ed91 e9f6 ac91
|
||||||
|
e2af bc2c 3f3f 9bff 88f4 7079 7e90 1e2e
|
||||||
|
cfbf 5a47 5f28 5d28 885d 8827 871b 912e
|
||||||
|
75dc 1e75 9793 d88f c488 fb3d 6adc 6f2a
|
||||||
|
7b27 536c 4f63 1fd0 068e 94b7 2c64 0118
|
||||||
|
6615 3654 5dce 9801 58d5 8353 69b4 5cc9
|
||||||
|
925a ed83 3a9a 5ac7 4878 0432 50c7 f376
|
||||||
|
6993 a8b4 58d9 2199 924c f97d a92f f1ef
|
||||||
|
332c fa49 d66e dd88 3e85 b6c9 2fd6 7697
|
||||||
|
5122 a88e faaf 57ed e67e 74ad dadc 0122
|
||||||
|
38f0 8ade bd70 da6e 4eca 4e2d dbdd 9af8
|
||||||
|
d15a 0ff6 94dd bc09 ca52 be33 21a0 6e73
|
||||||
|
d9ce e9fd f3cb 7673 1ff4 6ff9 fe55 6964
|
||||||
|
3efb 561d dd33 f2ce 7ee4 01bb 455d 6789
|
||||||
|
08b7 e7e4 6fc5 fa66 6c8e 3e92 9248 00ff
|
||||||
|
f00c 78d9 49ac 1fac be48 2b9e 9330 fc32
|
||||||
|
d486 fa58 aacf 6fea 68f6 4a6f 9175 a0d6
|
||||||
|
8269 f69a c1b9 fd79 973a 5504 5623 08c2
|
||||||
|
921f 991e b8c0 6071 cbd7 aa17 182c 6eb0
|
||||||
|
d641 731b db0f 8d59 0a40 2409 717d d187
|
||||||
|
061f 10a8 bf69 a65d bb48 76d8 44f8 453b
|
||||||
|
44ad 2b55 13d0 a82b 7a39 b50c fae1 2cf1
|
||||||
|
85d4 0219 b7a4 9452 af9a 4f5d d45e 475b
|
||||||
|
17c6 10ea 399c 8449 60b2 6f35 abd4 11ac
|
||||||
|
9f29 b3e5 eaa1 77ec dfd5 d1d1 7514 010d
|
||||||
|
fa9e 9330 1ac4 c4ab 4e49 fd61 0ad5 d962
|
||||||
|
5862 b443 1953 1726 388a a3d9 acec cb82
|
||||||
|
092d 07e0 bb85 177b 3e98 2849 46fa c377
|
||||||
|
73b2 9215 3a15 1ea4 8107 c9b0 4403 e5ac
|
||||||
|
8112 121b 8c6f de41 15be 8c5d 6495 e7d6
|
||||||
|
6d59 ecf3 1e64 807f 4a8d 4096 76d9 d346
|
||||||
|
70f0 0bf6 8fea e8b3 57a4 905b ee3a ca4a
|
||||||
|
1a66 a0c4 b841 ea49 37b9 411c 51cd b3c0
|
||||||
|
d82d dad2 5fce fa30 47a6 02dc 58d8 396d
|
||||||
|
5877 e979 fbcc c6c6 e57e b70e 0d37 2edf
|
||||||
|
1d71 fdd5 73f6 afea e8ce 911a 14f9 9608
|
||||||
|
aff4 df82 230b 98a7 6148 5896 7305 c149
|
||||||
|
1a51 0f4a 0f50 023c 925d 5933 45bc 7b7f
|
||||||
|
fbdd 5bde 7fee 6d83 299e ff61 643d 73e6
|
||||||
|
5e83 29a0 254d 8e2d 2d1b 4c91 95e8 5f32
|
||||||
|
fbdb eb24 95b6 bb42 1453 05c6 ab74 a19e
|
||||||
|
18c6 16df b7cf ad43 aaa6 2a45 1677 ad0b
|
||||||
|
14cd 1910 930d 54d7 6aaf d7d1 f448 dd79
|
||||||
|
6c4b b5f8 8ea1 ac91 23e0 6315 6360 e4e6
|
||||||
|
6174 406d 5e1f 12e8 2768 44a0 7905 3e51
|
||||||
|
005c 3bbb c7fe 9359 7ea2 58f8 1d45 007c
|
||||||
|
78d5 fcc6 83f9 2adc be5c 8638 8db2 f4c9
|
||||||
|
de55 6043 0e54 a358 f634 3ac3 3c16 2709
|
||||||
|
a498 7168 ad2a 8d67 a8eb 196d b379 ad0a
|
||||||
|
c65a c38a d1b0 6b0c 09f7 6376 17dd ba81
|
||||||
|
2285 b0b6 598e 8629 50f0 1a0a ab1f 6f31
|
||||||
|
ea2c 4b03 ea14 6df2 88ee f3e6 c1ee 1acb
|
||||||
|
272b 4db5 1c80 2732 8919 681a 996d 1029
|
||||||
|
88c6 51e5 d1a9 613d c215 46a3 6137 09fa
|
||||||
|
7459 c304 0303 9967 aa68 7d22 15be 9175
|
||||||
|
55f7 5426 a5d9 6159 9739 a678 66e4 c474
|
||||||
|
061d 2c69 d24d 4005 5433 c72b 80ca f6b3
|
||||||
|
10a4 d159 e60b c821 dd1d 98a1 7ed3 fe6b
|
||||||
|
dd98 c94c 0d0a 4daf d58f 0f90 952f 6868
|
||||||
|
8268 843e fc45 c9f0 f238 76e3 3061 8017
|
||||||
|
9ecd 5dba 5da1 2b09 140d 4fd2 0e14 439c
|
||||||
|
bfee c284 67df f246 0adc 0350 ebab 02a9
|
||||||
|
9b2b 7559 9003 5887 1fd3 5518 ff65 8b11
|
||||||
|
a75c b223 398a 81e7 d5ed d6e6 f183 0b6e
|
||||||
|
3628 eb7d 2042 2ace 5279 1597 9124 7f0b
|
||||||
|
fbdd 3acc 1e0d 7dc4 da7a e44e 0e43 e2b6
|
||||||
|
1c19 ab27 860c 8933 f6e0 9038 3304 7dad
|
||||||
|
214d 706b 4813 dcb2 9b4f d781 900b 23b6
|
||||||
|
1c91 36dc a5f6 eff9 af0c aaff 06f1 48e5
|
||||||
|
4433 2000 00
|
163
Godeps/_workspace/src/github.com/prometheus/common/expfmt/testdata/test.gz
generated
vendored
Normal file
163
Godeps/_workspace/src/github.com/prometheus/common/expfmt/testdata/test.gz
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
1f8b 0808 2aa1 c754 0003 7465 7874 00b5
|
||||||
|
5b5d 939b 3816 7def 5fa1 ea79 99a9 4d3c
|
||||||
|
601b db3c f4c3 5426 55f3 309b ca6e 7ab7
|
||||||
|
6a9e 281a d436 150c 04c4 a4bd 5df3 dff7
|
||||||
|
4a88 361f 025d 094f 1e92 34e8 1cae 8ea4
|
||||||
|
ab7b 04fd 03f9 ede3 ef9f c989 b122 28e9
|
||||||
|
b79a 562c 88eb 3264 499e 05e7 242a f38a
|
||||||
|
4679 1657 e4f1 44c9 6f8f 8f9f 896c 46d2
|
||||||
|
90d1 2c4a 6845 928c 749b aeee 7e20 8f7f
|
||||||
|
7cfe 8861 adea f339 2c2f 77fa a6af a730
|
||||||
|
8b53 5a3e dcff 7cff ee5b 1d66 2c49 e9c3
|
||||||
|
bdb3 f2ee ff22 ce12 027f 3101 9621 80ee
|
||||||
|
7659 90a8 28af 3366 8eeb 2042 f887 558b
|
||||||
|
7553 d158 a8a7 a4b1 d450 7259 2a69 84ee
|
||||||
|
e28a e4e7 3365 6512 dd40 d429 2e1b 6527
|
||||||
|
b96c e5ed 10da 6a6c 4c31 0043 cbf2 7213
|
||||||
|
9915 4c96 22ab 9816 48dc d02d 10d8 8440
|
||||||
|
050d ca30 3bd2 db89 ace2 5b22 b592 6fa9
|
||||||
|
e092 74a9 ec46 3403 0216 9647 7a8b cc3c
|
||||||
|
c565 29ba 9a6b 81e0 2de1 02b1 cd28 3a60
|
||||||
|
f8b9 ca53 5a2d 2f1c 2698 2c44 9e62 b294
|
||||||
|
f84a 6729 b029 4107 7a2c c3e2 b458 5a05
|
||||||
|
8b85 ac2a 164b 491b 2a4b 394d c01d d889
|
||||||
|
86c5 6225 c724 1642 2a48 2c75 144c 9632
|
||||||
|
1a60 3ba8 8ac1 ed68 f96a 57f2 5868 a9e6
|
||||||
|
b194 b325 b354 d40c 7e05 1665 0e45 dc89
|
||||||
|
d68a bdca dd38 fbd5 7aef dd84 90cb e21e
|
||||||
|
bcc3 6ab7 59df 8690 336e 9cc3 7eb5 396c
|
||||||
|
8df5 eeb0 425c 7bff 70d8 ad3c 47fe 712d
|
||||||
|
46a0 4fe8 fa60 96c7 16bc 4afe 4783 a70b
|
||||||
|
a30a dfcd ef09 cf2d eeab cd76 07af 74d8
|
||||||
|
d7fb 26b6 1a81 524c 6a0c 6a16 a675 cd9d
|
||||||
|
a67a abac 0c07 e98f d158 ac0c 5827 3c29
|
||||||
|
c694 819d 9144 0fb1 34ba 6604 6889 4c2c
|
||||||
|
edb4 4e73 2674 4e2c 1cce cab1 9ac0 4dd4
|
||||||
|
427a d359 ad26 fca4 4629 2d6a 81f5 3427
|
||||||
|
31d6 0c6b 32f5 ca4d 5942 8c7e 7aac a587
|
||||||
|
3423 3051 0fed 1667 959b f477 1ad5 1038
|
||||||
|
2b33 6802 c7aa 6560 fb26 b59a b16a 334a
|
||||||
|
a150 c6ae 0e0b c5ea 83f4 6f93 da4c f8ae
|
||||||
|
195d b408 537b 8644 6215 c119 b149 41d4
|
||||||
|
0e6a 460f 1dc0 c267 e1c1 5851 d08e 6a52
|
||||||
|
9749 1f34 230d 0283 334c 6bdf b527 f017
|
||||||
|
1368 1866 0cd0 66bb 3d1c b07a 619c 4e15
|
||||||
|
b09c 8529 7914 7f67 f5f9 8996 247f ee39
|
||||||
|
9e8a 9cc3 982a 8d4e 0b17 4fa6 e59d e2de
|
||||||
|
6b94 c7d0 edb5 e3dc bf53 4ac3 ff93 c70f
|
||||||
|
f7b0 8728 e3ac 0ac8 9c74 c292 3537 359e
|
||||||
|
6ccc 3030 65a3 0638 5786 87f9 96b0 79dc
|
||||||
|
8c31 1bb7 9d73 6673 1169 ad99 2918 ad85
|
||||||
|
de9c e914 195b 2dbd 2e08 8cb1 3fb3 62c0
|
||||||
|
eb84 7368 5ab1 d456 0ba1 1812 6868 d22c
|
||||||
|
f046 9269 6d1a 46b0 91e3 c2c9 a587 5939
|
||||||
|
356b 1673 e1f4 5e0d 2ddf d870 1988 8800
|
||||||
|
1bdb 352b 0623 0911 860d 239f c279 e1a4
|
||||||
|
c300 0d3d 9b05 1e2d 19ca b5e9 0453 1a30
|
||||||
|
bd5c 3898 8171 33c4 a245 d25a 379d 4023
|
||||||
|
27a6 1747 0fc1 bb37 3328 5a16 9d7f d3a9
|
||||||
|
32f4 637a 51b4 0823 0b67 8c46 2b83 3071
|
||||||
|
3a71 148e 4caf 0f06 84f4 71ce d65f 4021
|
||||||
|
7c98 e31d 9650 341c bb2d 52b1 9e27 5b6f
|
||||||
|
f79d 7758 5ae1 a6fc 1c5c 8f68 05cd 8b3a
|
||||||
|
685f 7a75 5d5d 5d81 a703 1252 5d2a 46cf
|
||||||
|
e4c3 e7ff 1096 9cc1 3515 3463 dc35 0d3f
|
||||||
|
1c9d 666c 8dde 740b 1819 6f18 d931 2ff3
|
||||||
|
9a25 1938 af4f 6f16 b373 919d 4246 a2ba
|
||||||
|
2c21 9ef4 42e8 4b52 b151 309d f6c7 b03e
|
||||||
|
d23b c58d bd33 7cf4 397c 099e e38a fc33
|
||||||
|
7c49 cef5 b963 7173 e83d 7986 7124 31ad
|
||||||
|
a232 2958 5e8e 2568 f1fd 47b6 570f aebf
|
||||||
|
1e3e 91f3 8a9b 9f0c 1ff5 06ec 3feb edf2
|
||||||
|
7a34 e230 6992 1834 0bce f49c 432d d498
|
||||||
|
db7f cbab a4b9 2acc f1d8 1bcf 73f4 4350
|
||||||
|
b7f1 569b c3de f1fc 35fd 87b3 1f86 068b
|
||||||
|
bc64 019f 66ed fc20 5ff8 a566 e681 2630
|
||||||
|
91db c610 6116 5152 67c9 0ba1 451e 9de6
|
||||||
|
e6a4 82b8 1fac a281 bbda aed7 9bdd c1df
|
||||||
|
1e36 3b88 7624 e49f 49c9 ea30 edf7 efbf
|
||||||
|
cd45 9c8c 4a86 7e60 ca26 de6a eb6e f707
|
||||||
|
dfe5 2a1e 3a71 c9a5 1ec4 1974 290e d23c
|
||||||
|
ff5a 17c1 7398 a435 0c47 bbc0 41c4 eb8c
|
||||||
|
fef5 d397 f75f 7e25 4d53 d236 ed86 8a22
|
||||||
|
edac 7154 7b47 1735 225a 7d94 d8e8 da76
|
||||||
|
7b45 54f4 cf30 ad43 587c dd4f 05d2 34e9
|
||||||
|
7e63 dfde 21cf 3964 cd34 2512 0497 2051
|
||||||
|
e590 9c68 5433 aa8a 5747 df9e 3ae1 21af
|
||||||
|
ddbd c671 c596 698b f696 a017 81c5 2725
|
||||||
|
d660 5334 df70 89bb 3641 8839 45d6 1bc5
|
||||||
|
9449 f308 966c 05d8 f048 83e8 44a3 af45
|
||||||
|
9e64 0c33 837e 14bf 9871 bdfb 1349 20ff
|
||||||
|
c12c e5f3 e84a 0549 e5bd cc31 f218 45ec
|
||||||
|
d650 46c6 d0aa cebe 2a17 8761 606f a9c8
|
||||||
|
12af 5ae4 430a 0815 76ab ee6a 6783 6365
|
||||||
|
d186 6f87 a55c 504f 17be 1124 2561 9742
|
||||||
|
b9a6 e69f a148 06b3 8057 fe98 87fb a8a4
|
||||||
|
21e3 8706 9e7f 30c5 42ec 1594 27e2 6ba4
|
||||||
|
ad31 38c9 00e8 af1d 5320 2bc3 ace2 27e9
|
||||||
|
00df ba9e 29bc ceae 4fd6 8d63 92c5 5080
|
||||||
|
65c7 e029 64d1 2968 7ecd e8d2 9f0d ff92
|
||||||
|
0bb4 1259 5234 242d 6ef8 8b49 5798 7e7c
|
||||||
|
31cf 5664 5163 92f9 dcb6 8cce bf31 dd72
|
||||||
|
3e91 1117 5234 29d2 359d 3dcd 8b99 fe74
|
||||||
|
799b 28cd bc69 9afc 784d 126d 1284 95d6
|
||||||
|
34f9 c978 e234 9ca6 3345 a046 5363 bd00
|
||||||
|
ef2f c55b 1088 d136 c518 0fef b79a d690
|
||||||
|
6dc2 228c 1276 11c9 feed 0759 ddbf 8db3
|
||||||
|
686b 3086 036e cdd6 3505 7377 fc7b 53c3
|
||||||
|
0ea5 343b b2d3 a052 6d27 e4f7 3061 bc3f
|
||||||
|
b07b 3fc9 eed1 d8b8 5ff2 1166 bd92 204c
|
||||||
|
f63e 5270 f971 5085 e722 a573 9bb1 6c41
|
||||||
|
5a08 a627 4a72 ed2e 3c81 db38 dbbd bee6
|
||||||
|
4a32 a8de 9238 284a 9ae6 613c 7a73 ade8
|
||||||
|
996c 7a7d 815d d267 5a96 72ec 4292 e5d9
|
||||||
|
7b71 c8c0 5d72 454b d8ab 5640 9480 16bc
|
||||||
|
f6e2 439b 444d 0dc7 dd7b cd62 4889 316c
|
||||||
|
6c4f 3495 e38e dacc 6603 47a8 368b d7cf
|
||||||
|
0569 3445 49c0 0f1e 9af2 549e b38c aab2
|
||||||
|
ced1 84d8 b805 58df cbf1 4334 337b 0c70
|
||||||
|
1dcf 37ea cc6c 473a d1bf 03b7 16a5 75cc
|
||||||
|
073e 4af3 8cb6 0535 94e6 2bba 6a7f f89e
|
||||||
|
b013 0c32 4c8c ab06 883d a71f 9141 af79
|
||||||
|
8f11 8598 8434 f373 a2c7 f2a6 f978 4920
|
||||||
|
2e6a d978 bbd6 e753 591e 778a 88ce 6f9b
|
||||||
|
ffd2 6ec9 3cf4 6b99 c88b 0289 e323 4543
|
||||||
|
a80a 8450 fade cc3e 4ebb ffcf a147 75c0
|
||||||
|
c659 6df6 fb1b 9035 47c6 9b95 b7f1 6fc1
|
||||||
|
26e8 76eb dd6a bbdb d8f1 3515 8303 c3bb
|
||||||
|
9af5 16b3 1cb2 82d8 e3a7 88a2 8490 9971
|
||||||
|
5048 4800 b68e 98e0 d74c f509 14ac 54d3
|
||||||
|
1e75 6a88 c914 d596 12b0 7017 f710 5750
|
||||||
|
2831 fa24 d42c 7d8d ad97 f9c1 ded7 8f9e
|
||||||
|
a2dd 1c87 88a1 b39f 2980 27a0 e730 8147
|
||||||
|
6661 16f1 ad57 a63e f1a6 4521 5296 b3e4
|
||||||
|
59d6 0895 daa7 fede 5c24 df7a e6a7 a299
|
||||||
|
d88e c467 46a4 4703 1e28 e787 41ed 8e15
|
||||||
|
9779 51c0 96d5 6ba4 dc97 10d1 2872 a11e
|
||||||
|
356f 930d f123 1f6b 8ab7 2018 3b5f 04a6
|
||||||
|
c964 aaa5 d107 232c 906a 9427 d7f8 2cfb
|
||||||
|
6875 cfb6 761d 6cf8 4ac3 a30a 5b66 2aa3
|
||||||
|
e8a7 32d3 4c5b 55dc 659d d2e0 7a0c 8f3e
|
||||||
|
bc27 1ca8 39b3 c771 2b56 0f0a f82a 5a35
|
||||||
|
f945 880a eb5a f5ae fff6 bca3 c572 2bde
|
||||||
|
d189 048a 58bc 0557 91ff 3538 aac7 b135
|
||||||
|
6fc6 27f8 fa25 8c71 bf4b b854 c67f c340
|
||||||
|
4d10 2f1f a929 62f1 8bb7 8b87 eaca 0eda
|
||||||
|
9a4b 3b1e ab1e a1eb 2116 bce2 ade7 b004
|
||||||
|
114b fd0a 997d fba9 a157 d41e 1a84 2a69
|
||||||
|
b547 1d83 ccfc 61b0 4388 db22 5dd5 d9f7
|
||||||
|
3261 b01f b507 33aa d027 5847 1976 a2dd
|
||||||
|
d6f1 77da 5865 26fe 30aa 5d13 46cf fd8d
|
||||||
|
6022 70f2 915b 38de 1cc4 3c17 25cc 854a
|
||||||
|
bc4b 6d8f 9ce8 4b01 c621 e665 22b8 72d2
|
||||||
|
7c8e 48c2 4afc d41c b7c1 08c2 34ba 48a7
|
||||||
|
de1e c149 d580 07f6 2bf8 4b59 0e29 bba3
|
||||||
|
9168 66fb 69a2 0b78 7558 c214 904d df3e
|
||||||
|
2ef8 2512 5f09 b4b7 a1f6 a5ec 3be5 6a44
|
||||||
|
6558 a887 5143 a9d8 6ee6 11af edf5 877b
|
||||||
|
d71b 7ca2 245e 1bbb db1b 9179 3724 f346
|
||||||
|
19c5 9ecb bf25 9729 9948 997d 42fe 7ad0
|
||||||
|
84a1 c992 238e b55d 8f54 53c0 b90d d568
|
||||||
|
1fb4 a6ba 1dd3 e813 017b 2643 aae1 c8f3
|
||||||
|
41f3 168d 7bf3 71df feee ff2d f9e8 431a
|
||||||
|
5200 00
|
@@ -175,9 +175,9 @@ http_response_size_bytes_count{handler="prometheus"} 119
|
|||||||
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
|
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
|
||||||
# TYPE process_cpu_seconds_total counter
|
# TYPE process_cpu_seconds_total counter
|
||||||
process_cpu_seconds_total 0.55
|
process_cpu_seconds_total 0.55
|
||||||
# HELP process_goroutines Number of goroutines that currently exist.
|
# HELP go_goroutines Number of goroutines that currently exist.
|
||||||
# TYPE process_goroutines gauge
|
# TYPE go_goroutines gauge
|
||||||
process_goroutines 70
|
go_goroutines 70
|
||||||
# HELP process_max_fds Maximum number of open file descriptors.
|
# HELP process_max_fds Maximum number of open file descriptors.
|
||||||
# TYPE process_max_fds gauge
|
# TYPE process_max_fds gauge
|
||||||
process_max_fds 8192
|
process_max_fds 8192
|
@@ -11,14 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Package text contains helper functions to parse and create text-based
|
package expfmt
|
||||||
// exchange formats. The package currently supports (only) version 0.0.4 of the
|
|
||||||
// exchange format. Should other versions be supported in the future, some
|
|
||||||
// versioning scheme has to be applied. Possibilities include separate packages
|
|
||||||
// or separate functions. The best way depends on the nature of future changes,
|
|
||||||
// which is the reason why no versioning scheme has been applied prematurely
|
|
||||||
// here.
|
|
||||||
package text
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -27,8 +20,8 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MetricFamilyToText converts a MetricFamily proto message into text format and
|
// MetricFamilyToText converts a MetricFamily proto message into text format and
|
||||||
@@ -79,7 +72,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
|||||||
case dto.MetricType_COUNTER:
|
case dto.MetricType_COUNTER:
|
||||||
if metric.Counter == nil {
|
if metric.Counter == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected counter in metric %s", metric,
|
"expected counter in metric %s %s", name, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
n, err = writeSample(
|
n, err = writeSample(
|
||||||
@@ -90,7 +83,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
|||||||
case dto.MetricType_GAUGE:
|
case dto.MetricType_GAUGE:
|
||||||
if metric.Gauge == nil {
|
if metric.Gauge == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected gauge in metric %s", metric,
|
"expected gauge in metric %s %s", name, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
n, err = writeSample(
|
n, err = writeSample(
|
||||||
@@ -101,7 +94,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
|||||||
case dto.MetricType_UNTYPED:
|
case dto.MetricType_UNTYPED:
|
||||||
if metric.Untyped == nil {
|
if metric.Untyped == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected untyped in metric %s", metric,
|
"expected untyped in metric %s %s", name, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
n, err = writeSample(
|
n, err = writeSample(
|
||||||
@@ -112,7 +105,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
|||||||
case dto.MetricType_SUMMARY:
|
case dto.MetricType_SUMMARY:
|
||||||
if metric.Summary == nil {
|
if metric.Summary == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected summary in metric %s", metric,
|
"expected summary in metric %s %s", name, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
for _, q := range metric.Summary.Quantile {
|
for _, q := range metric.Summary.Quantile {
|
||||||
@@ -144,7 +137,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
|||||||
case dto.MetricType_HISTOGRAM:
|
case dto.MetricType_HISTOGRAM:
|
||||||
if metric.Histogram == nil {
|
if metric.Histogram == nil {
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"expected summary in metric %s", metric,
|
"expected histogram in metric %s %s", name, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
infSeen := false
|
infSeen := false
|
||||||
@@ -191,7 +184,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
|||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return written, fmt.Errorf(
|
return written, fmt.Errorf(
|
||||||
"unexpected type in metric %s", metric,
|
"unexpected type in metric %s %s", name, metric,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
written += n
|
written += n
|
@@ -11,7 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package text
|
package expfmt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
@@ -11,7 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package text
|
package expfmt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/prometheus/common/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A stateFn is a function that represents a state in a state machine. By
|
// A stateFn is a function that represents a state in a state machine. By
|
||||||
@@ -46,9 +46,9 @@ func (e ParseError) Error() string {
|
|||||||
return fmt.Sprintf("text format parsing error in line %d: %s", e.Line, e.Msg)
|
return fmt.Sprintf("text format parsing error in line %d: %s", e.Line, e.Msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parser is used to parse the simple and flat text-based exchange format. Its
|
// TextParser is used to parse the simple and flat text-based exchange format. Its
|
||||||
// nil value is ready to use.
|
// nil value is ready to use.
|
||||||
type Parser struct {
|
type TextParser struct {
|
||||||
metricFamiliesByName map[string]*dto.MetricFamily
|
metricFamiliesByName map[string]*dto.MetricFamily
|
||||||
buf *bufio.Reader // Where the parsed input is read through.
|
buf *bufio.Reader // Where the parsed input is read through.
|
||||||
err error // Most recent error.
|
err error // Most recent error.
|
||||||
@@ -83,14 +83,21 @@ type Parser struct {
|
|||||||
// and exactly the same label set), the resulting MetricFamily will contain
|
// and exactly the same label set), the resulting MetricFamily will contain
|
||||||
// duplicate Metric proto messages. Similar is true for duplicate label
|
// duplicate Metric proto messages. Similar is true for duplicate label
|
||||||
// names. Checks for duplicates have to be performed separately, if required.
|
// names. Checks for duplicates have to be performed separately, if required.
|
||||||
|
// Also note that neither the metrics within each MetricFamily are sorted nor
|
||||||
|
// the label pairs within each Metric. Sorting is not required for the most
|
||||||
|
// frequent use of this method, which is sample ingestion in the Prometheus
|
||||||
|
// server. However, for presentation purposes, you might want to sort the
|
||||||
|
// metrics, and in some cases, you must sort the labels, e.g. for consumption by
|
||||||
|
// the metric family injection hook of the Prometheus registry.
|
||||||
//
|
//
|
||||||
// Summaries are a rather special beast. You would probably not use them in the
|
// Summaries and histograms are rather special beasts. You would probably not
|
||||||
// simple text format anyway. This method can deal with summaries if they are
|
// use them in the simple text format anyway. This method can deal with
|
||||||
// presented in exactly the way the text.Create function creates them.
|
// summaries and histograms if they are presented in exactly the way the
|
||||||
|
// text.Create function creates them.
|
||||||
//
|
//
|
||||||
// This method must not be called concurrently. If you want to parse different
|
// This method must not be called concurrently. If you want to parse different
|
||||||
// input concurrently, instantiate a separate Parser for each goroutine.
|
// input concurrently, instantiate a separate Parser for each goroutine.
|
||||||
func (p *Parser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricFamily, error) {
|
func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricFamily, error) {
|
||||||
p.reset(in)
|
p.reset(in)
|
||||||
for nextState := p.startOfLine; nextState != nil; nextState = nextState() {
|
for nextState := p.startOfLine; nextState != nil; nextState = nextState() {
|
||||||
// Magic happens here...
|
// Magic happens here...
|
||||||
@@ -104,7 +111,7 @@ func (p *Parser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricFamil
|
|||||||
return p.metricFamiliesByName, p.err
|
return p.metricFamiliesByName, p.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) reset(in io.Reader) {
|
func (p *TextParser) reset(in io.Reader) {
|
||||||
p.metricFamiliesByName = map[string]*dto.MetricFamily{}
|
p.metricFamiliesByName = map[string]*dto.MetricFamily{}
|
||||||
if p.buf == nil {
|
if p.buf == nil {
|
||||||
p.buf = bufio.NewReader(in)
|
p.buf = bufio.NewReader(in)
|
||||||
@@ -125,7 +132,7 @@ func (p *Parser) reset(in io.Reader) {
|
|||||||
|
|
||||||
// startOfLine represents the state where the next byte read from p.buf is the
|
// startOfLine represents the state where the next byte read from p.buf is the
|
||||||
// start of a line (or whitespace leading up to it).
|
// start of a line (or whitespace leading up to it).
|
||||||
func (p *Parser) startOfLine() stateFn {
|
func (p *TextParser) startOfLine() stateFn {
|
||||||
p.lineCount++
|
p.lineCount++
|
||||||
if p.skipBlankTab(); p.err != nil {
|
if p.skipBlankTab(); p.err != nil {
|
||||||
// End of input reached. This is the only case where
|
// End of input reached. This is the only case where
|
||||||
@@ -144,7 +151,7 @@ func (p *Parser) startOfLine() stateFn {
|
|||||||
|
|
||||||
// startComment represents the state where the next byte read from p.buf is the
|
// startComment represents the state where the next byte read from p.buf is the
|
||||||
// start of a comment (or whitespace leading up to it).
|
// start of a comment (or whitespace leading up to it).
|
||||||
func (p *Parser) startComment() stateFn {
|
func (p *TextParser) startComment() stateFn {
|
||||||
if p.skipBlankTab(); p.err != nil {
|
if p.skipBlankTab(); p.err != nil {
|
||||||
return nil // Unexpected end of input.
|
return nil // Unexpected end of input.
|
||||||
}
|
}
|
||||||
@@ -205,7 +212,7 @@ func (p *Parser) startComment() stateFn {
|
|||||||
|
|
||||||
// readingMetricName represents the state where the last byte read (now in
|
// readingMetricName represents the state where the last byte read (now in
|
||||||
// p.currentByte) is the first byte of a metric name.
|
// p.currentByte) is the first byte of a metric name.
|
||||||
func (p *Parser) readingMetricName() stateFn {
|
func (p *TextParser) readingMetricName() stateFn {
|
||||||
if p.readTokenAsMetricName(); p.err != nil {
|
if p.readTokenAsMetricName(); p.err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -232,7 +239,7 @@ func (p *Parser) readingMetricName() stateFn {
|
|||||||
// readingLabels represents the state where the last byte read (now in
|
// readingLabels represents the state where the last byte read (now in
|
||||||
// p.currentByte) is either the first byte of the label set (i.e. a '{'), or the
|
// p.currentByte) is either the first byte of the label set (i.e. a '{'), or the
|
||||||
// first byte of the value (otherwise).
|
// first byte of the value (otherwise).
|
||||||
func (p *Parser) readingLabels() stateFn {
|
func (p *TextParser) readingLabels() stateFn {
|
||||||
// Summaries/histograms are special. We have to reset the
|
// Summaries/histograms are special. We have to reset the
|
||||||
// currentLabels map, currentQuantile and currentBucket before starting to
|
// currentLabels map, currentQuantile and currentBucket before starting to
|
||||||
// read labels.
|
// read labels.
|
||||||
@@ -250,7 +257,7 @@ func (p *Parser) readingLabels() stateFn {
|
|||||||
|
|
||||||
// startLabelName represents the state where the next byte read from p.buf is
|
// startLabelName represents the state where the next byte read from p.buf is
|
||||||
// the start of a label name (or whitespace leading up to it).
|
// the start of a label name (or whitespace leading up to it).
|
||||||
func (p *Parser) startLabelName() stateFn {
|
func (p *TextParser) startLabelName() stateFn {
|
||||||
if p.skipBlankTab(); p.err != nil {
|
if p.skipBlankTab(); p.err != nil {
|
||||||
return nil // Unexpected end of input.
|
return nil // Unexpected end of input.
|
||||||
}
|
}
|
||||||
@@ -290,7 +297,7 @@ func (p *Parser) startLabelName() stateFn {
|
|||||||
|
|
||||||
// startLabelValue represents the state where the next byte read from p.buf is
|
// startLabelValue represents the state where the next byte read from p.buf is
|
||||||
// the start of a (quoted) label value (or whitespace leading up to it).
|
// the start of a (quoted) label value (or whitespace leading up to it).
|
||||||
func (p *Parser) startLabelValue() stateFn {
|
func (p *TextParser) startLabelValue() stateFn {
|
||||||
if p.skipBlankTab(); p.err != nil {
|
if p.skipBlankTab(); p.err != nil {
|
||||||
return nil // Unexpected end of input.
|
return nil // Unexpected end of input.
|
||||||
}
|
}
|
||||||
@@ -348,7 +355,7 @@ func (p *Parser) startLabelValue() stateFn {
|
|||||||
|
|
||||||
// readingValue represents the state where the last byte read (now in
|
// readingValue represents the state where the last byte read (now in
|
||||||
// p.currentByte) is the first byte of the sample value (i.e. a float).
|
// p.currentByte) is the first byte of the sample value (i.e. a float).
|
||||||
func (p *Parser) readingValue() stateFn {
|
func (p *TextParser) readingValue() stateFn {
|
||||||
// When we are here, we have read all the labels, so for the
|
// When we are here, we have read all the labels, so for the
|
||||||
// special case of a summary/histogram, we can finally find out
|
// special case of a summary/histogram, we can finally find out
|
||||||
// if the metric already exists.
|
// if the metric already exists.
|
||||||
@@ -436,7 +443,7 @@ func (p *Parser) readingValue() stateFn {
|
|||||||
|
|
||||||
// startTimestamp represents the state where the next byte read from p.buf is
|
// startTimestamp represents the state where the next byte read from p.buf is
|
||||||
// the start of the timestamp (or whitespace leading up to it).
|
// the start of the timestamp (or whitespace leading up to it).
|
||||||
func (p *Parser) startTimestamp() stateFn {
|
func (p *TextParser) startTimestamp() stateFn {
|
||||||
if p.skipBlankTab(); p.err != nil {
|
if p.skipBlankTab(); p.err != nil {
|
||||||
return nil // Unexpected end of input.
|
return nil // Unexpected end of input.
|
||||||
}
|
}
|
||||||
@@ -462,7 +469,7 @@ func (p *Parser) startTimestamp() stateFn {
|
|||||||
|
|
||||||
// readingHelp represents the state where the last byte read (now in
|
// readingHelp represents the state where the last byte read (now in
|
||||||
// p.currentByte) is the first byte of the docstring after 'HELP'.
|
// p.currentByte) is the first byte of the docstring after 'HELP'.
|
||||||
func (p *Parser) readingHelp() stateFn {
|
func (p *TextParser) readingHelp() stateFn {
|
||||||
if p.currentMF.Help != nil {
|
if p.currentMF.Help != nil {
|
||||||
p.parseError(fmt.Sprintf("second HELP line for metric name %q", p.currentMF.GetName()))
|
p.parseError(fmt.Sprintf("second HELP line for metric name %q", p.currentMF.GetName()))
|
||||||
return nil
|
return nil
|
||||||
@@ -477,7 +484,7 @@ func (p *Parser) readingHelp() stateFn {
|
|||||||
|
|
||||||
// readingType represents the state where the last byte read (now in
|
// readingType represents the state where the last byte read (now in
|
||||||
// p.currentByte) is the first byte of the type hint after 'HELP'.
|
// p.currentByte) is the first byte of the type hint after 'HELP'.
|
||||||
func (p *Parser) readingType() stateFn {
|
func (p *TextParser) readingType() stateFn {
|
||||||
if p.currentMF.Type != nil {
|
if p.currentMF.Type != nil {
|
||||||
p.parseError(fmt.Sprintf("second TYPE line for metric name %q, or TYPE reported after samples", p.currentMF.GetName()))
|
p.parseError(fmt.Sprintf("second TYPE line for metric name %q, or TYPE reported after samples", p.currentMF.GetName()))
|
||||||
return nil
|
return nil
|
||||||
@@ -497,7 +504,7 @@ func (p *Parser) readingType() stateFn {
|
|||||||
|
|
||||||
// parseError sets p.err to a ParseError at the current line with the given
|
// parseError sets p.err to a ParseError at the current line with the given
|
||||||
// message.
|
// message.
|
||||||
func (p *Parser) parseError(msg string) {
|
func (p *TextParser) parseError(msg string) {
|
||||||
p.err = ParseError{
|
p.err = ParseError{
|
||||||
Line: p.lineCount,
|
Line: p.lineCount,
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
@@ -506,7 +513,7 @@ func (p *Parser) parseError(msg string) {
|
|||||||
|
|
||||||
// skipBlankTab reads (and discards) bytes from p.buf until it encounters a byte
|
// skipBlankTab reads (and discards) bytes from p.buf until it encounters a byte
|
||||||
// that is neither ' ' nor '\t'. That byte is left in p.currentByte.
|
// that is neither ' ' nor '\t'. That byte is left in p.currentByte.
|
||||||
func (p *Parser) skipBlankTab() {
|
func (p *TextParser) skipBlankTab() {
|
||||||
for {
|
for {
|
||||||
if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil || !isBlankOrTab(p.currentByte) {
|
if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil || !isBlankOrTab(p.currentByte) {
|
||||||
return
|
return
|
||||||
@@ -516,7 +523,7 @@ func (p *Parser) skipBlankTab() {
|
|||||||
|
|
||||||
// skipBlankTabIfCurrentBlankTab works exactly as skipBlankTab but doesn't do
|
// skipBlankTabIfCurrentBlankTab works exactly as skipBlankTab but doesn't do
|
||||||
// anything if p.currentByte is neither ' ' nor '\t'.
|
// anything if p.currentByte is neither ' ' nor '\t'.
|
||||||
func (p *Parser) skipBlankTabIfCurrentBlankTab() {
|
func (p *TextParser) skipBlankTabIfCurrentBlankTab() {
|
||||||
if isBlankOrTab(p.currentByte) {
|
if isBlankOrTab(p.currentByte) {
|
||||||
p.skipBlankTab()
|
p.skipBlankTab()
|
||||||
}
|
}
|
||||||
@@ -526,7 +533,7 @@ func (p *Parser) skipBlankTabIfCurrentBlankTab() {
|
|||||||
// first byte considered is the byte already read (now in p.currentByte). The
|
// first byte considered is the byte already read (now in p.currentByte). The
|
||||||
// first whitespace byte encountered is still copied into p.currentByte, but not
|
// first whitespace byte encountered is still copied into p.currentByte, but not
|
||||||
// into p.currentToken.
|
// into p.currentToken.
|
||||||
func (p *Parser) readTokenUntilWhitespace() {
|
func (p *TextParser) readTokenUntilWhitespace() {
|
||||||
p.currentToken.Reset()
|
p.currentToken.Reset()
|
||||||
for p.err == nil && !isBlankOrTab(p.currentByte) && p.currentByte != '\n' {
|
for p.err == nil && !isBlankOrTab(p.currentByte) && p.currentByte != '\n' {
|
||||||
p.currentToken.WriteByte(p.currentByte)
|
p.currentToken.WriteByte(p.currentByte)
|
||||||
@@ -540,7 +547,7 @@ func (p *Parser) readTokenUntilWhitespace() {
|
|||||||
// p.currentToken. If recognizeEscapeSequence is true, two escape sequences are
|
// p.currentToken. If recognizeEscapeSequence is true, two escape sequences are
|
||||||
// recognized: '\\' tranlates into '\', and '\n' into a line-feed character. All
|
// recognized: '\\' tranlates into '\', and '\n' into a line-feed character. All
|
||||||
// other escape sequences are invalid and cause an error.
|
// other escape sequences are invalid and cause an error.
|
||||||
func (p *Parser) readTokenUntilNewline(recognizeEscapeSequence bool) {
|
func (p *TextParser) readTokenUntilNewline(recognizeEscapeSequence bool) {
|
||||||
p.currentToken.Reset()
|
p.currentToken.Reset()
|
||||||
escaped := false
|
escaped := false
|
||||||
for p.err == nil {
|
for p.err == nil {
|
||||||
@@ -573,7 +580,7 @@ func (p *Parser) readTokenUntilNewline(recognizeEscapeSequence bool) {
|
|||||||
// The first byte considered is the byte already read (now in p.currentByte).
|
// The first byte considered is the byte already read (now in p.currentByte).
|
||||||
// The first byte not part of a metric name is still copied into p.currentByte,
|
// The first byte not part of a metric name is still copied into p.currentByte,
|
||||||
// but not into p.currentToken.
|
// but not into p.currentToken.
|
||||||
func (p *Parser) readTokenAsMetricName() {
|
func (p *TextParser) readTokenAsMetricName() {
|
||||||
p.currentToken.Reset()
|
p.currentToken.Reset()
|
||||||
if !isValidMetricNameStart(p.currentByte) {
|
if !isValidMetricNameStart(p.currentByte) {
|
||||||
return
|
return
|
||||||
@@ -591,7 +598,7 @@ func (p *Parser) readTokenAsMetricName() {
|
|||||||
// The first byte considered is the byte already read (now in p.currentByte).
|
// The first byte considered is the byte already read (now in p.currentByte).
|
||||||
// The first byte not part of a label name is still copied into p.currentByte,
|
// The first byte not part of a label name is still copied into p.currentByte,
|
||||||
// but not into p.currentToken.
|
// but not into p.currentToken.
|
||||||
func (p *Parser) readTokenAsLabelName() {
|
func (p *TextParser) readTokenAsLabelName() {
|
||||||
p.currentToken.Reset()
|
p.currentToken.Reset()
|
||||||
if !isValidLabelNameStart(p.currentByte) {
|
if !isValidLabelNameStart(p.currentByte) {
|
||||||
return
|
return
|
||||||
@@ -610,7 +617,7 @@ func (p *Parser) readTokenAsLabelName() {
|
|||||||
// last read byte in p.currentByte, this method ignores p.currentByte and starts
|
// last read byte in p.currentByte, this method ignores p.currentByte and starts
|
||||||
// with reading a new byte from p.buf. The first byte not part of a label value
|
// with reading a new byte from p.buf. The first byte not part of a label value
|
||||||
// is still copied into p.currentByte, but not into p.currentToken.
|
// is still copied into p.currentByte, but not into p.currentToken.
|
||||||
func (p *Parser) readTokenAsLabelValue() {
|
func (p *TextParser) readTokenAsLabelValue() {
|
||||||
p.currentToken.Reset()
|
p.currentToken.Reset()
|
||||||
escaped := false
|
escaped := false
|
||||||
for {
|
for {
|
||||||
@@ -644,7 +651,7 @@ func (p *Parser) readTokenAsLabelValue() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) setOrCreateCurrentMF() {
|
func (p *TextParser) setOrCreateCurrentMF() {
|
||||||
p.currentIsSummaryCount = false
|
p.currentIsSummaryCount = false
|
||||||
p.currentIsSummarySum = false
|
p.currentIsSummarySum = false
|
||||||
p.currentIsHistogramCount = false
|
p.currentIsHistogramCount = false
|
@@ -11,7 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package text
|
package expfmt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
@@ -22,9 +22,7 @@ import (
|
|||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
var parser Parser
|
func testTextParse(t testing.TB) {
|
||||||
|
|
||||||
func testParse(t testing.TB) {
|
|
||||||
var scenarios = []struct {
|
var scenarios = []struct {
|
||||||
in string
|
in string
|
||||||
out []*dto.MetricFamily
|
out []*dto.MetricFamily
|
||||||
@@ -419,17 +417,17 @@ request_duration_microseconds_count 2693
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func TestTextParse(t *testing.T) {
|
||||||
testParse(t)
|
testTextParse(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkParse(b *testing.B) {
|
func BenchmarkTextParse(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
testParse(b)
|
testTextParse(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testParseError(t testing.TB) {
|
func testTextParseError(t testing.TB) {
|
||||||
var scenarios = []struct {
|
var scenarios = []struct {
|
||||||
in string
|
in string
|
||||||
err string
|
err string
|
||||||
@@ -577,12 +575,12 @@ metric_bucket{le="bla"} 3.14
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseError(t *testing.T) {
|
func TestTextParseError(t *testing.T) {
|
||||||
testParseError(t)
|
testTextParseError(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkParseError(b *testing.B) {
|
func BenchmarkParseError(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
testParseError(b)
|
testTextParseError(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -22,28 +22,23 @@ import (
|
|||||||
// For our purposes, FNV-1A 64-bit is used.
|
// For our purposes, FNV-1A 64-bit is used.
|
||||||
type Fingerprint uint64
|
type Fingerprint uint64
|
||||||
|
|
||||||
func (f Fingerprint) String() string {
|
// FingerprintFromString transforms a string representation into a Fingerprint.
|
||||||
return fmt.Sprintf("%016x", uint64(f))
|
func FingerprintFromString(s string) (Fingerprint, error) {
|
||||||
|
num, err := strconv.ParseUint(s, 16, 64)
|
||||||
|
return Fingerprint(num), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Less implements sort.Interface.
|
// ParseFingerprint parses the input string into a fingerprint.
|
||||||
func (f Fingerprint) Less(o Fingerprint) bool {
|
func ParseFingerprint(s string) (Fingerprint, error) {
|
||||||
return f < o
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal implements sort.Interface.
|
|
||||||
func (f Fingerprint) Equal(o Fingerprint) bool {
|
|
||||||
return f == o
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadFromString transforms a string representation into a Fingerprint.
|
|
||||||
func (f *Fingerprint) LoadFromString(s string) error {
|
|
||||||
num, err := strconv.ParseUint(s, 16, 64)
|
num, err := strconv.ParseUint(s, 16, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
*f = Fingerprint(num)
|
return Fingerprint(num), nil
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
func (f Fingerprint) String() string {
|
||||||
|
return fmt.Sprintf("%016x", uint64(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fingerprints represents a collection of Fingerprint subject to a given
|
// Fingerprints represents a collection of Fingerprint subject to a given
|
188
Godeps/_workspace/src/github.com/prometheus/common/model/labels.go
generated
vendored
Normal file
188
Godeps/_workspace/src/github.com/prometheus/common/model/labels.go
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
// 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 (
|
||||||
|
// AlertNameLabel is the name of the label containing the an alert's name.
|
||||||
|
AlertNameLabel = "alertname"
|
||||||
|
|
||||||
|
// 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 = "exported_"
|
||||||
|
|
||||||
|
// MetricNameLabel is the label name indicating the metric name of a
|
||||||
|
// timeseries.
|
||||||
|
MetricNameLabel = "__name__"
|
||||||
|
|
||||||
|
// SchemeLabel is the name of the label that holds the scheme on which to
|
||||||
|
// scrape a target.
|
||||||
|
SchemeLabel = "__scheme__"
|
||||||
|
|
||||||
|
// AddressLabel is the name of the label that holds the address of
|
||||||
|
// a scrape target.
|
||||||
|
AddressLabel = "__address__"
|
||||||
|
|
||||||
|
// MetricsPathLabel is the name of the label that holds the path on which to
|
||||||
|
// scrape a target.
|
||||||
|
MetricsPathLabel = "__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 = "job"
|
||||||
|
|
||||||
|
// InstanceLabel is the label name used for the instance label.
|
||||||
|
InstanceLabel = "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]
|
||||||
|
}
|
@@ -18,6 +18,42 @@ import (
|
|||||||
"testing"
|
"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) {
|
func testLabelValues(t testing.TB) {
|
||||||
var scenarios = []struct {
|
var scenarios = []struct {
|
||||||
in LabelValues
|
in LabelValues
|
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
|
||||||
|
}
|
@@ -14,7 +14,6 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -24,19 +23,27 @@ var separator = []byte{0}
|
|||||||
|
|
||||||
// A Metric is similar to a LabelSet, but the key difference is that a Metric is
|
// 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.
|
// a singleton and refers to one and only one stream of samples.
|
||||||
type Metric map[LabelName]LabelValue
|
type Metric LabelSet
|
||||||
|
|
||||||
// Equal compares the fingerprints of both metrics.
|
// Equal compares the metrics.
|
||||||
func (m Metric) Equal(o Metric) bool {
|
func (m Metric) Equal(o Metric) bool {
|
||||||
return m.Fingerprint().Equal(o.Fingerprint())
|
return LabelSet(m).Equal(LabelSet(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before compares the fingerprints of both metrics.
|
// Before compares the metrics' underlying label sets.
|
||||||
func (m Metric) Before(o Metric) bool {
|
func (m Metric) Before(o Metric) bool {
|
||||||
return m.Fingerprint().Less(o.Fingerprint())
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements Stringer.
|
|
||||||
func (m Metric) String() string {
|
func (m Metric) String() string {
|
||||||
metricName, hasName := m[MetricNameLabel]
|
metricName, hasName := m[MetricNameLabel]
|
||||||
numLabels := len(m) - 1
|
numLabels := len(m) - 1
|
||||||
@@ -64,69 +71,11 @@ func (m Metric) String() string {
|
|||||||
|
|
||||||
// Fingerprint returns a Metric's Fingerprint.
|
// Fingerprint returns a Metric's Fingerprint.
|
||||||
func (m Metric) Fingerprint() Fingerprint {
|
func (m Metric) Fingerprint() Fingerprint {
|
||||||
return metricToFingerprint(m)
|
return LabelSet(m).Fingerprint()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone returns a copy of the Metric.
|
// FastFingerprint returns a Metric's Fingerprint calculated by a faster hashing
|
||||||
func (m Metric) Clone() Metric {
|
// algorithm, which is, however, more susceptible to hash collisions.
|
||||||
clone := Metric{}
|
func (m Metric) FastFingerprint() Fingerprint {
|
||||||
for k, v := range m {
|
return LabelSet(m).FastFingerprint()
|
||||||
clone[k] = v
|
|
||||||
}
|
|
||||||
return clone
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeFromLabelSet merges a label set into this Metric, prefixing a collision
|
|
||||||
// prefix to the label names merged from the label set where required.
|
|
||||||
func (m Metric) MergeFromLabelSet(labels LabelSet, collisionPrefix LabelName) {
|
|
||||||
for k, v := range labels {
|
|
||||||
if collisionPrefix != "" {
|
|
||||||
for {
|
|
||||||
if _, exists := m[k]; !exists {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
k = collisionPrefix + k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) Delete(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)
|
|
||||||
}
|
}
|
83
Godeps/_workspace/src/github.com/prometheus/common/model/metric_test.go
generated
vendored
Normal file
83
Godeps/_workspace/src/github.com/prometheus/common/model/metric_test.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
@@ -11,5 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Package model contains core representation of Prometheus client primitives.
|
// Package model contains common data structures that are shared across
|
||||||
|
// Prometheus componenets and libraries.
|
||||||
package model
|
package model
|
@@ -17,6 +17,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"hash"
|
"hash"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,36 +47,71 @@ func getHashAndBuf() *hashAndBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func putHashAndBuf(hb *hashAndBuf) {
|
func putHashAndBuf(hb *hashAndBuf) {
|
||||||
|
hb.h.Reset()
|
||||||
|
hb.b.Reset()
|
||||||
hashAndBufPool.Put(hb)
|
hashAndBufPool.Put(hb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LabelsToSignature returns a unique signature (i.e., fingerprint) for a given
|
// LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a
|
||||||
// label set.
|
// 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 {
|
func LabelsToSignature(labels map[string]string) uint64 {
|
||||||
if len(labels) == 0 {
|
if len(labels) == 0 {
|
||||||
return emptyLabelSignature
|
return emptyLabelSignature
|
||||||
}
|
}
|
||||||
|
|
||||||
var result uint64
|
labelNames := make([]string, 0, len(labels))
|
||||||
|
for labelName := range labels {
|
||||||
|
labelNames = append(labelNames, labelName)
|
||||||
|
}
|
||||||
|
sort.Strings(labelNames)
|
||||||
|
|
||||||
hb := getHashAndBuf()
|
hb := getHashAndBuf()
|
||||||
defer putHashAndBuf(hb)
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
for labelName, labelValue := range labels {
|
for _, labelName := range labelNames {
|
||||||
hb.b.WriteString(labelName)
|
hb.b.WriteString(labelName)
|
||||||
hb.b.WriteByte(SeparatorByte)
|
hb.b.WriteByte(SeparatorByte)
|
||||||
hb.b.WriteString(labelValue)
|
hb.b.WriteString(labels[labelName])
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
hb.h.Write(hb.b.Bytes())
|
hb.h.Write(hb.b.Bytes())
|
||||||
result ^= hb.h.Sum64()
|
|
||||||
hb.h.Reset()
|
|
||||||
hb.b.Reset()
|
hb.b.Reset()
|
||||||
}
|
}
|
||||||
return result
|
return hb.h.Sum64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// metricToFingerprint works exactly as LabelsToSignature but takes a Metric as
|
// labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as
|
||||||
// parameter (rather than a label map) and returns a Fingerprint.
|
// parameter (rather than a label map) and returns a Fingerprint.
|
||||||
func metricToFingerprint(m Metric) Fingerprint {
|
func labelSetToFingerprint(ls LabelSet) Fingerprint {
|
||||||
if len(m) == 0 {
|
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)
|
return Fingerprint(emptyLabelSignature)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +119,7 @@ func metricToFingerprint(m Metric) Fingerprint {
|
|||||||
hb := getHashAndBuf()
|
hb := getHashAndBuf()
|
||||||
defer putHashAndBuf(hb)
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
for labelName, labelValue := range m {
|
for labelName, labelValue := range ls {
|
||||||
hb.b.WriteString(string(labelName))
|
hb.b.WriteString(string(labelName))
|
||||||
hb.b.WriteByte(SeparatorByte)
|
hb.b.WriteByte(SeparatorByte)
|
||||||
hb.b.WriteString(string(labelValue))
|
hb.b.WriteString(string(labelValue))
|
||||||
@@ -97,13 +133,15 @@ func metricToFingerprint(m Metric) Fingerprint {
|
|||||||
|
|
||||||
// SignatureForLabels works like LabelsToSignature but takes a Metric as
|
// SignatureForLabels works like LabelsToSignature but takes a Metric as
|
||||||
// parameter (rather than a label map) and only includes the labels with the
|
// parameter (rather than a label map) and only includes the labels with the
|
||||||
// specified LabelNames into the signature calculation.
|
// specified LabelNames into the signature calculation. The labels passed in
|
||||||
func SignatureForLabels(m Metric, labels LabelNames) uint64 {
|
// will be sorted by this function.
|
||||||
|
func SignatureForLabels(m Metric, labels ...LabelName) uint64 {
|
||||||
if len(m) == 0 || len(labels) == 0 {
|
if len(m) == 0 || len(labels) == 0 {
|
||||||
return emptyLabelSignature
|
return emptyLabelSignature
|
||||||
}
|
}
|
||||||
|
|
||||||
var result uint64
|
sort.Sort(LabelNames(labels))
|
||||||
|
|
||||||
hb := getHashAndBuf()
|
hb := getHashAndBuf()
|
||||||
defer putHashAndBuf(hb)
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
@@ -111,12 +149,11 @@ func SignatureForLabels(m Metric, labels LabelNames) uint64 {
|
|||||||
hb.b.WriteString(string(label))
|
hb.b.WriteString(string(label))
|
||||||
hb.b.WriteByte(SeparatorByte)
|
hb.b.WriteByte(SeparatorByte)
|
||||||
hb.b.WriteString(string(m[label]))
|
hb.b.WriteString(string(m[label]))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
hb.h.Write(hb.b.Bytes())
|
hb.h.Write(hb.b.Bytes())
|
||||||
result ^= hb.h.Sum64()
|
|
||||||
hb.h.Reset()
|
|
||||||
hb.b.Reset()
|
hb.b.Reset()
|
||||||
}
|
}
|
||||||
return result
|
return hb.h.Sum64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignatureWithoutLabels works like LabelsToSignature but takes a Metric as
|
// SignatureWithoutLabels works like LabelsToSignature but takes a Metric as
|
||||||
@@ -127,24 +164,27 @@ func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 {
|
|||||||
return emptyLabelSignature
|
return emptyLabelSignature
|
||||||
}
|
}
|
||||||
|
|
||||||
var result uint64
|
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()
|
hb := getHashAndBuf()
|
||||||
defer putHashAndBuf(hb)
|
defer putHashAndBuf(hb)
|
||||||
|
|
||||||
for labelName, labelValue := range m {
|
for _, labelName := range labelNames {
|
||||||
if _, exclude := labels[labelName]; exclude {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
hb.b.WriteString(string(labelName))
|
hb.b.WriteString(string(labelName))
|
||||||
hb.b.WriteByte(SeparatorByte)
|
hb.b.WriteByte(SeparatorByte)
|
||||||
hb.b.WriteString(string(labelValue))
|
hb.b.WriteString(string(m[labelName]))
|
||||||
|
hb.b.WriteByte(SeparatorByte)
|
||||||
hb.h.Write(hb.b.Bytes())
|
hb.h.Write(hb.b.Bytes())
|
||||||
result ^= hb.h.Sum64()
|
|
||||||
hb.h.Reset()
|
|
||||||
hb.b.Reset()
|
hb.b.Reset()
|
||||||
}
|
}
|
||||||
if result == 0 {
|
return hb.h.Sum64()
|
||||||
return emptyLabelSignature
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
@@ -30,7 +30,7 @@ func TestLabelsToSignature(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: map[string]string{"name": "garland, briggs", "fear": "love is not enough"},
|
in: map[string]string{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
out: 12952432476264840823,
|
out: 5799056148416392346,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,21 +45,45 @@ func TestLabelsToSignature(t *testing.T) {
|
|||||||
|
|
||||||
func TestMetricToFingerprint(t *testing.T) {
|
func TestMetricToFingerprint(t *testing.T) {
|
||||||
var scenarios = []struct {
|
var scenarios = []struct {
|
||||||
in Metric
|
in LabelSet
|
||||||
out Fingerprint
|
out Fingerprint
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
in: Metric{},
|
in: LabelSet{},
|
||||||
out: 14695981039346656037,
|
out: 14695981039346656037,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
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,
|
out: 12952432476264840823,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
for i, scenario := range scenarios {
|
||||||
actual := metricToFingerprint(scenario.in)
|
actual := labelSetToFastFingerprint(scenario.in)
|
||||||
|
|
||||||
if actual != scenario.out {
|
if actual != scenario.out {
|
||||||
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
||||||
@@ -81,12 +105,12 @@ func TestSignatureForLabels(t *testing.T) {
|
|||||||
{
|
{
|
||||||
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
labels: LabelNames{"fear", "name"},
|
labels: LabelNames{"fear", "name"},
|
||||||
out: 12952432476264840823,
|
out: 5799056148416392346,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
|
||||||
labels: LabelNames{"fear", "name"},
|
labels: LabelNames{"fear", "name"},
|
||||||
out: 12952432476264840823,
|
out: 5799056148416392346,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
@@ -101,7 +125,7 @@ func TestSignatureForLabels(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
for i, scenario := range scenarios {
|
||||||
actual := SignatureForLabels(scenario.in, scenario.labels)
|
actual := SignatureForLabels(scenario.in, scenario.labels...)
|
||||||
|
|
||||||
if actual != scenario.out {
|
if actual != scenario.out {
|
||||||
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
|
||||||
@@ -128,17 +152,17 @@ func TestSignatureWithoutLabels(t *testing.T) {
|
|||||||
{
|
{
|
||||||
in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
|
||||||
labels: map[LabelName]struct{}{"foo": struct{}{}},
|
labels: map[LabelName]struct{}{"foo": struct{}{}},
|
||||||
out: 12952432476264840823,
|
out: 5799056148416392346,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
labels: map[LabelName]struct{}{},
|
labels: map[LabelName]struct{}{},
|
||||||
out: 12952432476264840823,
|
out: 5799056148416392346,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
in: Metric{"name": "garland, briggs", "fear": "love is not enough"},
|
||||||
labels: nil,
|
labels: nil,
|
||||||
out: 12952432476264840823,
|
out: 5799056148416392346,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,21 +188,21 @@ func BenchmarkLabelToSignatureScalar(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkLabelToSignatureSingle(b *testing.B) {
|
func BenchmarkLabelToSignatureSingle(b *testing.B) {
|
||||||
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value"}, 5147259542624943964)
|
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value"}, 5146282821936882169)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkLabelToSignatureDouble(b *testing.B) {
|
func BenchmarkLabelToSignatureDouble(b *testing.B) {
|
||||||
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value"}, 18269973311206963528)
|
benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkLabelToSignatureTriple(b *testing.B) {
|
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"}, 15738406913934009676)
|
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, m Metric, e Fingerprint) {
|
func benchmarkMetricToFingerprint(b *testing.B, ls LabelSet, e Fingerprint) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
if a := metricToFingerprint(m); a != e {
|
if a := labelSetToFingerprint(ls); a != e {
|
||||||
b.Fatalf("expected signature of %d for %s, got %d", e, m, a)
|
b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,18 +212,42 @@ func BenchmarkMetricToFingerprintScalar(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMetricToFingerprintSingle(b *testing.B) {
|
func BenchmarkMetricToFingerprintSingle(b *testing.B) {
|
||||||
benchmarkMetricToFingerprint(b, Metric{"first-label": "first-label-value"}, 5147259542624943964)
|
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5146282821936882169)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMetricToFingerprintDouble(b *testing.B) {
|
func BenchmarkMetricToFingerprintDouble(b *testing.B) {
|
||||||
benchmarkMetricToFingerprint(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value"}, 18269973311206963528)
|
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMetricToFingerprintTriple(b *testing.B) {
|
func BenchmarkMetricToFingerprintTriple(b *testing.B) {
|
||||||
benchmarkMetricToFingerprint(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676)
|
benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEmptyLabelSignature(t *testing.T) {
|
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 BenchmarkEmptyLabelSignature(b *testing.B) {
|
||||||
input := []map[string]string{nil, {}}
|
input := []map[string]string{nil, {}}
|
||||||
|
|
||||||
var ms runtime.MemStats
|
var ms runtime.MemStats
|
||||||
@@ -214,11 +262,11 @@ func TestEmptyLabelSignature(t *testing.T) {
|
|||||||
runtime.ReadMemStats(&ms)
|
runtime.ReadMemStats(&ms)
|
||||||
|
|
||||||
if got := ms.Alloc; alloc != got {
|
if got := ms.Alloc; alloc != got {
|
||||||
t.Fatal("expected LabelsToSignature with empty labels not to perform allocations")
|
b.Fatal("expected LabelsToSignature with empty labels not to perform allocations")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmarkMetricToFingerprintConc(b *testing.B, m Metric, e Fingerprint, concLevel int) {
|
func benchmarkMetricToFastFingerprintConc(b *testing.B, ls LabelSet, e Fingerprint, concLevel int) {
|
||||||
var start, end sync.WaitGroup
|
var start, end sync.WaitGroup
|
||||||
start.Add(1)
|
start.Add(1)
|
||||||
end.Add(concLevel)
|
end.Add(concLevel)
|
||||||
@@ -227,8 +275,8 @@ func benchmarkMetricToFingerprintConc(b *testing.B, m Metric, e Fingerprint, con
|
|||||||
go func() {
|
go func() {
|
||||||
start.Wait()
|
start.Wait()
|
||||||
for j := b.N / concLevel; j >= 0; j-- {
|
for j := b.N / concLevel; j >= 0; j-- {
|
||||||
if a := metricToFingerprint(m); a != e {
|
if a := labelSetToFastFingerprint(ls); a != e {
|
||||||
b.Fatalf("expected signature of %d for %s, got %d", e, m, a)
|
b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end.Done()
|
end.Done()
|
||||||
@@ -239,18 +287,18 @@ func benchmarkMetricToFingerprintConc(b *testing.B, m Metric, e Fingerprint, con
|
|||||||
end.Wait()
|
end.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMetricToFingerprintTripleConc1(b *testing.B) {
|
func BenchmarkMetricToFastFingerprintTripleConc1(b *testing.B) {
|
||||||
benchmarkMetricToFingerprintConc(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 1)
|
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMetricToFingerprintTripleConc2(b *testing.B) {
|
func BenchmarkMetricToFastFingerprintTripleConc2(b *testing.B) {
|
||||||
benchmarkMetricToFingerprintConc(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 2)
|
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMetricToFingerprintTripleConc4(b *testing.B) {
|
func BenchmarkMetricToFastFingerprintTripleConc4(b *testing.B) {
|
||||||
benchmarkMetricToFingerprintConc(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 4)
|
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkMetricToFingerprintTripleConc8(b *testing.B) {
|
func BenchmarkMetricToFastFingerprintTripleConc8(b *testing.B) {
|
||||||
benchmarkMetricToFingerprintConc(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 8)
|
benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 8)
|
||||||
}
|
}
|
230
Godeps/_workspace/src/github.com/prometheus/common/model/time.go
generated
vendored
Normal file
230
Godeps/_workspace/src/github.com/prometheus/common/model/time.go
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
// 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 {
|
||||||
|
return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
@@ -15,13 +15,13 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
native_time "time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestComparators(t *testing.T) {
|
func TestComparators(t *testing.T) {
|
||||||
t1a := TimestampFromUnix(0)
|
t1a := TimeFromUnix(0)
|
||||||
t1b := TimestampFromUnix(0)
|
t1b := TimeFromUnix(0)
|
||||||
t2 := TimestampFromUnix(2*second - 1)
|
t2 := TimeFromUnix(2*second - 1)
|
||||||
|
|
||||||
if !t1a.Equal(t1b) {
|
if !t1a.Equal(t1b) {
|
||||||
t.Fatalf("Expected %s to be equal to %s", t1a, t1b)
|
t.Fatalf("Expected %s to be equal to %s", t1a, t1b)
|
||||||
@@ -45,21 +45,21 @@ func TestComparators(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTimestampConversions(t *testing.T) {
|
func TestTimeConversions(t *testing.T) {
|
||||||
unixSecs := int64(1136239445)
|
unixSecs := int64(1136239445)
|
||||||
unixNsecs := int64(123456789)
|
unixNsecs := int64(123456789)
|
||||||
unixNano := unixSecs*1000000000 + unixNsecs
|
unixNano := unixSecs*1e9 + unixNsecs
|
||||||
|
|
||||||
t1 := native_time.Unix(unixSecs, unixNsecs-unixNsecs%nanosPerTick)
|
t1 := time.Unix(unixSecs, unixNsecs-unixNsecs%nanosPerTick)
|
||||||
t2 := native_time.Unix(unixSecs, unixNsecs)
|
t2 := time.Unix(unixSecs, unixNsecs)
|
||||||
|
|
||||||
ts := TimestampFromUnixNano(unixNano)
|
ts := TimeFromUnixNano(unixNano)
|
||||||
if !ts.Time().Equal(t1) {
|
if !ts.Time().Equal(t1) {
|
||||||
t.Fatalf("Expected %s, got %s", t1, ts.Time())
|
t.Fatalf("Expected %s, got %s", t1, ts.Time())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test available precision.
|
// Test available precision.
|
||||||
ts = TimestampFromTime(t2)
|
ts = TimeFromUnixNano(t2.UnixNano())
|
||||||
if !ts.Time().Equal(t1) {
|
if !ts.Time().Equal(t1) {
|
||||||
t.Fatalf("Expected %s, got %s", t1, ts.Time())
|
t.Fatalf("Expected %s, got %s", t1, ts.Time())
|
||||||
}
|
}
|
||||||
@@ -70,10 +70,10 @@ func TestTimestampConversions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDuration(t *testing.T) {
|
func TestDuration(t *testing.T) {
|
||||||
duration := native_time.Second + native_time.Minute + native_time.Hour
|
duration := time.Second + time.Minute + time.Hour
|
||||||
goTime := native_time.Unix(1136239445, 0)
|
goTime := time.Unix(1136239445, 0)
|
||||||
|
|
||||||
ts := TimestampFromTime(goTime)
|
ts := TimeFromUnix(goTime.Unix())
|
||||||
if !goTime.Add(duration).Equal(ts.Add(duration).Time()) {
|
if !goTime.Add(duration).Equal(ts.Add(duration).Time()) {
|
||||||
t.Fatalf("Expected %s to be equal to %s", goTime.Add(duration), ts.Add(duration))
|
t.Fatalf("Expected %s to be equal to %s", goTime.Add(duration), ts.Add(duration))
|
||||||
}
|
}
|
395
Godeps/_workspace/src/github.com/prometheus/common/model/value.go
generated
vendored
Normal file
395
Godeps/_workspace/src/github.com/prometheus/common/model/value.go
generated
vendored
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
// 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 []byte(fmt.Sprintf("[%s,%s]", t, v)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (s *SamplePair) UnmarshalJSON(b []byte) error {
|
||||||
|
v := [...]json.Unmarshaler{&s.Timestamp, &s.Value}
|
||||||
|
return json.Unmarshal(b, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 `json:"metric"`
|
||||||
|
Value SampleValue `json:"value"`
|
||||||
|
Timestamp Time `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (s Sample) MarshalJSON() ([]byte, error) {
|
||||||
|
v := struct {
|
||||||
|
Metric Metric `json:"metric"`
|
||||||
|
Value SamplePair `json:"value"`
|
||||||
|
}{
|
||||||
|
Metric: s.Metric,
|
||||||
|
Value: SamplePair{
|
||||||
|
Timestamp: s.Timestamp,
|
||||||
|
Value: s.Value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(&v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (s *Sample) UnmarshalJSON(b []byte) error {
|
||||||
|
v := struct {
|
||||||
|
Metric Metric `json:"metric"`
|
||||||
|
Value SamplePair `json:"value"`
|
||||||
|
}{
|
||||||
|
Metric: s.Metric,
|
||||||
|
Value: SamplePair{
|
||||||
|
Timestamp: s.Timestamp,
|
||||||
|
Value: s.Value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Metric = v.Metric
|
||||||
|
s.Timestamp = v.Value.Timestamp
|
||||||
|
s.Value = v.Value.Value
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (s Scalar) MarshalJSON() ([]byte, error) {
|
||||||
|
v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64)
|
||||||
|
return json.Marshal([...]interface{}{s.Timestamp, string(v)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (s *Scalar) UnmarshalJSON(b []byte) error {
|
||||||
|
var f string
|
||||||
|
v := [...]interface{}{&s.Timestamp, &f}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := strconv.ParseFloat(f, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error parsing sample value: %s", err)
|
||||||
|
}
|
||||||
|
s.Value = SampleValue(value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (s String) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal([]interface{}{s.Timestamp, s.Value})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (s *String) UnmarshalJSON(b []byte) error {
|
||||||
|
v := [...]interface{}{&s.Timestamp, &s.Value}
|
||||||
|
return json.Unmarshal(b, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
}
|
362
Godeps/_workspace/src/github.com/prometheus/common/model/value_test.go
generated
vendored
Normal file
362
Godeps/_workspace/src/github.com/prometheus/common/model/value_test.go
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
// 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"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSamplePairJSON(t *testing.T) {
|
||||||
|
input := []struct {
|
||||||
|
plain string
|
||||||
|
value SamplePair
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
plain: `[1234.567,"123.1"]`,
|
||||||
|
value: SamplePair{
|
||||||
|
Value: 123.1,
|
||||||
|
Timestamp: 1234567,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range input {
|
||||||
|
b, err := json.Marshal(test.value)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(b) != test.plain {
|
||||||
|
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var sp SamplePair
|
||||||
|
err = json.Unmarshal(b, &sp)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if sp != test.value {
|
||||||
|
t.Errorf("decoding error: expected %v, got %v", test.value, sp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSampleJSON(t *testing.T) {
|
||||||
|
input := []struct {
|
||||||
|
plain string
|
||||||
|
value Sample
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
plain: `{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]}`,
|
||||||
|
value: Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "test_metric",
|
||||||
|
},
|
||||||
|
Value: 123.1,
|
||||||
|
Timestamp: 1234567,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range input {
|
||||||
|
b, err := json.Marshal(test.value)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(b) != test.plain {
|
||||||
|
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var sv Sample
|
||||||
|
err = json.Unmarshal(b, &sv)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(sv, test.value) {
|
||||||
|
t.Errorf("decoding error: expected %v, got %v", test.value, sv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVectorJSON(t *testing.T) {
|
||||||
|
input := []struct {
|
||||||
|
plain string
|
||||||
|
value Vector
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
plain: `[]`,
|
||||||
|
value: Vector{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plain: `[{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]}]`,
|
||||||
|
value: Vector{&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "test_metric",
|
||||||
|
},
|
||||||
|
Value: 123.1,
|
||||||
|
Timestamp: 1234567,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plain: `[{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]},{"metric":{"foo":"bar"},"value":[1.234,"+Inf"]}]`,
|
||||||
|
value: Vector{
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
MetricNameLabel: "test_metric",
|
||||||
|
},
|
||||||
|
Value: 123.1,
|
||||||
|
Timestamp: 1234567,
|
||||||
|
},
|
||||||
|
&Sample{
|
||||||
|
Metric: Metric{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
Value: SampleValue(math.Inf(1)),
|
||||||
|
Timestamp: 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range input {
|
||||||
|
b, err := json.Marshal(test.value)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(b) != test.plain {
|
||||||
|
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var vec Vector
|
||||||
|
err = json.Unmarshal(b, &vec)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(vec, test.value) {
|
||||||
|
t.Errorf("decoding error: expected %v, got %v", test.value, vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScalarJSON(t *testing.T) {
|
||||||
|
input := []struct {
|
||||||
|
plain string
|
||||||
|
value Scalar
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
plain: `[123.456,"456"]`,
|
||||||
|
value: Scalar{
|
||||||
|
Timestamp: 123456,
|
||||||
|
Value: 456,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plain: `[123123.456,"+Inf"]`,
|
||||||
|
value: Scalar{
|
||||||
|
Timestamp: 123123456,
|
||||||
|
Value: SampleValue(math.Inf(1)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plain: `[123123.456,"-Inf"]`,
|
||||||
|
value: Scalar{
|
||||||
|
Timestamp: 123123456,
|
||||||
|
Value: SampleValue(math.Inf(-1)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range input {
|
||||||
|
b, err := json.Marshal(test.value)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(b) != test.plain {
|
||||||
|
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var sv Scalar
|
||||||
|
err = json.Unmarshal(b, &sv)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv != test.value {
|
||||||
|
t.Errorf("decoding error: expected %v, got %v", test.value, sv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringJSON(t *testing.T) {
|
||||||
|
input := []struct {
|
||||||
|
plain string
|
||||||
|
value String
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
plain: `[123.456,"test"]`,
|
||||||
|
value: String{
|
||||||
|
Timestamp: 123456,
|
||||||
|
Value: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plain: `[123123.456,"台北"]`,
|
||||||
|
value: String{
|
||||||
|
Timestamp: 123123456,
|
||||||
|
Value: "台北",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range input {
|
||||||
|
b, err := json.Marshal(test.value)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(b) != test.plain {
|
||||||
|
t.Errorf("encoding error: expected %q, got %q", test.plain, b)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var sv String
|
||||||
|
err = json.Unmarshal(b, &sv)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if sv != test.value {
|
||||||
|
t.Errorf("decoding error: expected %v, got %v", test.value, sv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -29,6 +29,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
cadvisor "github.com/google/cadvisor/info/v1"
|
cadvisor "github.com/google/cadvisor/info/v1"
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
@@ -38,9 +39,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/master/ports"
|
"k8s.io/kubernetes/pkg/master/ports"
|
||||||
"k8s.io/kubernetes/pkg/util"
|
"k8s.io/kubernetes/pkg/util"
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/extraction"
|
|
||||||
"github.com/prometheus/client_golang/model"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// KubeletMetric stores metrics scraped from the kubelet server's /metric endpoint.
|
// KubeletMetric stores metrics scraped from the kubelet server's /metric endpoint.
|
||||||
@@ -63,10 +61,13 @@ func (a KubeletMetricByLatency) Len() int { return len(a) }
|
|||||||
func (a KubeletMetricByLatency) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
func (a KubeletMetricByLatency) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
func (a KubeletMetricByLatency) Less(i, j int) bool { return a[i].Latency > a[j].Latency }
|
func (a KubeletMetricByLatency) Less(i, j int) bool { return a[i].Latency > a[j].Latency }
|
||||||
|
|
||||||
// KubeletMetricIngester implements extraction.Ingester
|
// ParseKubeletMetrics reads metrics from the kubelet server running on the given node
|
||||||
type kubeletMetricIngester []KubeletMetric
|
func ParseKubeletMetrics(metricsBlob string) ([]KubeletMetric, error) {
|
||||||
|
samples, err := extractMetricSamples(metricsBlob)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
func (k *kubeletMetricIngester) Ingest(samples model.Samples) error {
|
|
||||||
acceptedMethods := sets.NewString(
|
acceptedMethods := sets.NewString(
|
||||||
metrics.PodWorkerLatencyKey,
|
metrics.PodWorkerLatencyKey,
|
||||||
metrics.PodWorkerStartLatencyKey,
|
metrics.PodWorkerStartLatencyKey,
|
||||||
@@ -78,6 +79,7 @@ func (k *kubeletMetricIngester) Ingest(samples model.Samples) error {
|
|||||||
metrics.DockerErrorsKey,
|
metrics.DockerErrorsKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var kms []KubeletMetric
|
||||||
for _, sample := range samples {
|
for _, sample := range samples {
|
||||||
const prefix = metrics.KubeletSubsystem + "_"
|
const prefix = metrics.KubeletSubsystem + "_"
|
||||||
metricName := string(sample.Metric[model.MetricNameLabel])
|
metricName := string(sample.Metric[model.MetricNameLabel])
|
||||||
@@ -105,16 +107,14 @@ func (k *kubeletMetricIngester) Ingest(samples model.Samples) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*k = append(*k, KubeletMetric{operation, method, quantile, time.Duration(int64(latency)) * time.Microsecond})
|
kms = append(kms, KubeletMetric{
|
||||||
|
operation,
|
||||||
|
method,
|
||||||
|
quantile,
|
||||||
|
time.Duration(int64(latency)) * time.Microsecond,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return nil
|
return kms, nil
|
||||||
}
|
|
||||||
|
|
||||||
// ReadKubeletMetrics reads metrics from the kubelet server running on the given node
|
|
||||||
func ParseKubeletMetrics(metricsBlob string) ([]KubeletMetric, error) {
|
|
||||||
var ingester kubeletMetricIngester
|
|
||||||
err := extraction.Processor004.ProcessSingle(strings.NewReader(metricsBlob), &ingester, &extraction.ProcessOptions{})
|
|
||||||
return ingester, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HighLatencyKubeletOperations logs and counts the high latency metrics exported by the kubelet server via /metrics.
|
// HighLatencyKubeletOperations logs and counts the high latency metrics exported by the kubelet server via /metrics.
|
||||||
|
@@ -50,8 +50,8 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/watch"
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/prometheus/client_golang/extraction"
|
"github.com/prometheus/common/expfmt"
|
||||||
"github.com/prometheus/client_golang/model"
|
"github.com/prometheus/common/model"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@@ -1817,34 +1817,6 @@ type LatencyMetric struct {
|
|||||||
Latency time.Duration
|
Latency time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// latencyMetricIngestor implements extraction.Ingester
|
|
||||||
type latencyMetricIngester []LatencyMetric
|
|
||||||
|
|
||||||
func (l *latencyMetricIngester) Ingest(samples model.Samples) error {
|
|
||||||
for _, sample := range samples {
|
|
||||||
// Example line:
|
|
||||||
// apiserver_request_latencies_summary{resource="namespaces",verb="LIST",quantile="0.99"} 908
|
|
||||||
if sample.Metric[model.MetricNameLabel] != "apiserver_request_latencies_summary" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
resource := string(sample.Metric["resource"])
|
|
||||||
verb := string(sample.Metric["verb"])
|
|
||||||
latency := sample.Value
|
|
||||||
quantile, err := strconv.ParseFloat(string(sample.Metric[model.QuantileLabel]), 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*l = append(*l, LatencyMetric{
|
|
||||||
verb,
|
|
||||||
resource,
|
|
||||||
quantile,
|
|
||||||
time.Duration(int64(latency)) * time.Microsecond,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LatencyMetricByLatency implements sort.Interface for []LatencyMetric based on
|
// LatencyMetricByLatency implements sort.Interface for []LatencyMetric based on
|
||||||
// the latency field.
|
// the latency field.
|
||||||
type LatencyMetricByLatency []LatencyMetric
|
type LatencyMetricByLatency []LatencyMetric
|
||||||
@@ -1858,9 +1830,37 @@ func ReadLatencyMetrics(c *client.Client) ([]LatencyMetric, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var ingester latencyMetricIngester
|
|
||||||
err = extraction.Processor004.ProcessSingle(strings.NewReader(body), &ingester, &extraction.ProcessOptions{})
|
samples, err := extractMetricSamples(body)
|
||||||
return ingester, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var metrics []LatencyMetric
|
||||||
|
for _, sample := range samples {
|
||||||
|
// Example line:
|
||||||
|
// apiserver_request_latencies_summary{resource="namespaces",verb="LIST",quantile="0.99"} 908
|
||||||
|
if sample.Metric[model.MetricNameLabel] != "apiserver_request_latencies_summary" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
resource := string(sample.Metric["resource"])
|
||||||
|
verb := string(sample.Metric["verb"])
|
||||||
|
latency := sample.Value
|
||||||
|
quantile, err := strconv.ParseFloat(string(sample.Metric[model.QuantileLabel]), 64)
|
||||||
|
if err != nil {
|
||||||
|
return metrics, err
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics = append(metrics, LatencyMetric{
|
||||||
|
verb,
|
||||||
|
resource,
|
||||||
|
quantile,
|
||||||
|
time.Duration(int64(latency)) * time.Microsecond,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return metrics, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints summary metrics for request types with latency above threshold
|
// Prints summary metrics for request types with latency above threshold
|
||||||
@@ -2070,3 +2070,29 @@ func waitForClusterSize(c *client.Client, size int, timeout time.Duration) error
|
|||||||
}
|
}
|
||||||
return fmt.Errorf("timeout waiting %v for cluster size to be %d", timeout, size)
|
return fmt.Errorf("timeout waiting %v for cluster size to be %d", timeout, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractMetricSamples parses the prometheus metric samples from the input string.
|
||||||
|
func extractMetricSamples(metricsBlob string) ([]*model.Sample, error) {
|
||||||
|
dec, err := expfmt.NewDecoder(strings.NewReader(metricsBlob),
|
||||||
|
http.Header{"Content-Type": []string{"text/plain"}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
decoder := expfmt.SampleDecoder{
|
||||||
|
Dec: dec,
|
||||||
|
Opts: &expfmt.DecodeOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
|
var samples []*model.Sample
|
||||||
|
for {
|
||||||
|
var v model.Vector
|
||||||
|
if err = decoder.Decode(&v); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
// Expected loop termination condition.
|
||||||
|
return samples, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
samples = append(samples, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user