Make Prometheus understand the new text format v0.0.4.
Change-Id: I42b834528c9c75d3d97443612bb05ce198ba4dc4
This commit is contained in:
parent
46fc7a3748
commit
ad3452a46c
|
@ -40,7 +40,16 @@ func ProcessorForRequestHeader(header http.Header) (Processor, error) {
|
|||
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
|
||||
|
||||
|
|
|
@ -71,6 +71,21 @@ func testDiscriminatorHttpHeader(t test.Tester) {
|
|||
output: nil,
|
||||
err: fmt.Errorf("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: fmt.Errorf("Unrecognized API version 0.0.3"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, scenario := range scenarios {
|
||||
|
|
|
@ -31,10 +31,10 @@ type metricFamilyProcessor struct{}
|
|||
//
|
||||
// See http://godoc.org/github.com/matttproud/golang_protobuf_extensions/ext for
|
||||
// more details.
|
||||
var MetricFamilyProcessor = new(metricFamilyProcessor)
|
||||
var MetricFamilyProcessor = &metricFamilyProcessor{}
|
||||
|
||||
func (m *metricFamilyProcessor) ProcessSingle(i io.Reader, out Ingester, o *ProcessOptions) error {
|
||||
family := new(dto.MetricFamily)
|
||||
family := &dto.MetricFamily{}
|
||||
|
||||
for {
|
||||
family.Reset()
|
||||
|
@ -43,30 +43,33 @@ func (m *metricFamilyProcessor) ProcessSingle(i io.Reader, out Ingester, o *Proc
|
|||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
switch *family.Type {
|
||||
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
|
||||
}
|
||||
if err := extractMetricFamily(out, o, family); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extractMetricFamily(out Ingester, o *ProcessOptions, family *dto.MetricFamily) error {
|
||||
switch *family.Type {
|
||||
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
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ import (
|
|||
// ProcessOptions dictates how the interpreted stream should be rendered for
|
||||
// consumption.
|
||||
type ProcessOptions struct {
|
||||
// Timestamp is added to each value interpreted from the stream.
|
||||
// Timestamp is added to each value from the stream that has no explicit
|
||||
// timestamp set.
|
||||
Timestamp model.Timestamp
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2014 Prometheus Team
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package 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
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2014 Prometheus Team
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package 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]*Result{
|
||||
"mf1": {
|
||||
Samples: model.Samples{
|
||||
&model.Sample{
|
||||
Metric: model.Metric{model.MetricNameLabel: "mf1", "label": "value1"},
|
||||
Value: -3.14,
|
||||
Timestamp: 123,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{model.MetricNameLabel: "mf1", "label": "value2"},
|
||||
Value: 42,
|
||||
Timestamp: ts,
|
||||
},
|
||||
},
|
||||
},
|
||||
"mf2": {
|
||||
Samples: 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 []*Result
|
||||
}
|
||||
|
||||
func (i *testIngester) Ingest(r *Result) error {
|
||||
i.results = append(i.results, r)
|
||||
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.Samples[0].Metric[model.MetricNameLabel]]
|
||||
if !ok {
|
||||
t.Fatalf(
|
||||
"Unexpected metric name %q",
|
||||
r.Samples[0].Metric[model.MetricNameLabel],
|
||||
)
|
||||
}
|
||||
sort.Sort(expected.Samples)
|
||||
sort.Sort(r.Samples)
|
||||
if !expected.equal(r) {
|
||||
t.Errorf("expected %s, got %s", expected, r)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue