Add support for optionally missing +Inf bucket in protobuf.

Also, clean up style issues in metricfamilyprocessor.go.
This commit is contained in:
beorn7 2015-02-12 20:55:56 +01:00
parent a7c56882af
commit b37ca982a9
3 changed files with 140 additions and 57 deletions

View File

@ -16,6 +16,7 @@ package extraction
import ( import (
"fmt" "fmt"
"io" "io"
"math"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
@ -85,7 +86,10 @@ func extractCounter(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error
continue continue
} }
sample := new(model.Sample) sample := &model.Sample{
Metric: model.Metric{},
Value: model.SampleValue(m.Counter.GetValue()),
}
samples = append(samples, sample) samples = append(samples, sample)
if m.TimestampMs != nil { if m.TimestampMs != nil {
@ -93,16 +97,12 @@ func extractCounter(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error
} else { } else {
sample.Timestamp = o.Timestamp sample.Timestamp = o.Timestamp
} }
sample.Metric = model.Metric{}
metric := sample.Metric
metric := sample.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
metric[model.MetricNameLabel] = model.LabelValue(f.GetName()) metric[model.MetricNameLabel] = model.LabelValue(f.GetName())
sample.Value = model.SampleValue(m.Counter.GetValue())
} }
return out.Ingest(samples) return out.Ingest(samples)
@ -116,7 +116,10 @@ func extractGauge(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error {
continue continue
} }
sample := new(model.Sample) sample := &model.Sample{
Metric: model.Metric{},
Value: model.SampleValue(m.Gauge.GetValue()),
}
samples = append(samples, sample) samples = append(samples, sample)
if m.TimestampMs != nil { if m.TimestampMs != nil {
@ -124,16 +127,12 @@ func extractGauge(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error {
} else { } else {
sample.Timestamp = o.Timestamp sample.Timestamp = o.Timestamp
} }
sample.Metric = model.Metric{}
metric := sample.Metric
metric := sample.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
metric[model.MetricNameLabel] = model.LabelValue(f.GetName()) metric[model.MetricNameLabel] = model.LabelValue(f.GetName())
sample.Value = model.SampleValue(m.Gauge.GetValue())
} }
return out.Ingest(samples) return out.Ingest(samples)
@ -153,48 +152,50 @@ func extractSummary(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error
} }
for _, q := range m.Summary.Quantile { for _, q := range m.Summary.Quantile {
sample := new(model.Sample) sample := &model.Sample{
Metric: model.Metric{},
Value: model.SampleValue(q.GetValue()),
Timestamp: timestamp,
}
samples = append(samples, sample) samples = append(samples, sample)
sample.Timestamp = timestamp
sample.Metric = model.Metric{}
metric := sample.Metric metric := sample.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
// BUG(matt): Update other names to "quantile". // BUG(matt): Update other names to "quantile".
metric[model.LabelName("quantile")] = model.LabelValue(fmt.Sprint(q.GetQuantile())) metric[model.LabelName("quantile")] = model.LabelValue(fmt.Sprint(q.GetQuantile()))
metric[model.MetricNameLabel] = model.LabelValue(f.GetName()) metric[model.MetricNameLabel] = model.LabelValue(f.GetName())
sample.Value = model.SampleValue(q.GetValue())
} }
if m.Summary.SampleSum != nil { if m.Summary.SampleSum != nil {
sum := new(model.Sample) sum := &model.Sample{
sum.Timestamp = timestamp Metric: model.Metric{},
metric := model.Metric{} Value: model.SampleValue(m.Summary.GetSampleSum()),
Timestamp: timestamp,
}
samples = append(samples, sum)
metric := sum.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum") metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
sum.Metric = metric
sum.Value = model.SampleValue(m.Summary.GetSampleSum())
samples = append(samples, sum)
} }
if m.Summary.SampleCount != nil { if m.Summary.SampleCount != nil {
count := new(model.Sample) count := &model.Sample{
count.Timestamp = timestamp Metric: model.Metric{},
metric := model.Metric{} Value: model.SampleValue(m.Summary.GetSampleCount()),
Timestamp: timestamp,
}
samples = append(samples, count)
metric := count.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count") metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
count.Metric = metric
count.Value = model.SampleValue(m.Summary.GetSampleCount())
samples = append(samples, count)
} }
} }
@ -209,7 +210,10 @@ func extractUntyped(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error
continue continue
} }
sample := new(model.Sample) sample := &model.Sample{
Metric: model.Metric{},
Value: model.SampleValue(m.Untyped.GetValue()),
}
samples = append(samples, sample) samples = append(samples, sample)
if m.TimestampMs != nil { if m.TimestampMs != nil {
@ -217,16 +221,12 @@ func extractUntyped(out Ingester, o *ProcessOptions, f *dto.MetricFamily) error
} else { } else {
sample.Timestamp = o.Timestamp sample.Timestamp = o.Timestamp
} }
sample.Metric = model.Metric{}
metric := sample.Metric
metric := sample.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
metric[model.MetricNameLabel] = model.LabelValue(f.GetName()) metric[model.MetricNameLabel] = model.LabelValue(f.GetName())
sample.Value = model.SampleValue(m.Untyped.GetValue())
} }
return out.Ingest(samples) return out.Ingest(samples)
@ -245,49 +245,72 @@ func extractHistogram(out Ingester, o *ProcessOptions, f *dto.MetricFamily) erro
timestamp = model.TimestampFromUnixNano(*m.TimestampMs * 1000000) timestamp = model.TimestampFromUnixNano(*m.TimestampMs * 1000000)
} }
infSeen := false
for _, q := range m.Histogram.Bucket { for _, q := range m.Histogram.Bucket {
sample := new(model.Sample) sample := &model.Sample{
Metric: model.Metric{},
Value: model.SampleValue(q.GetCumulativeCount()),
Timestamp: timestamp,
}
samples = append(samples, sample) samples = append(samples, sample)
sample.Timestamp = timestamp
sample.Metric = model.Metric{}
metric := sample.Metric metric := sample.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
metric[model.LabelName("le")] = model.LabelValue(fmt.Sprint(q.GetUpperBound())) metric[model.LabelName("le")] = model.LabelValue(fmt.Sprint(q.GetUpperBound()))
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket") metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
sample.Value = model.SampleValue(q.GetCumulativeCount()) if math.IsInf(q.GetUpperBound(), +1) {
infSeen = true
}
} }
// TODO: If +Inf bucket is missing, add it.
if m.Histogram.SampleSum != nil { if m.Histogram.SampleSum != nil {
sum := new(model.Sample) sum := &model.Sample{
sum.Timestamp = timestamp Metric: model.Metric{},
metric := model.Metric{} Value: model.SampleValue(m.Histogram.GetSampleSum()),
Timestamp: timestamp,
}
samples = append(samples, sum)
metric := sum.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum") metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
sum.Metric = metric
sum.Value = model.SampleValue(m.Histogram.GetSampleSum())
samples = append(samples, sum)
} }
if m.Histogram.SampleCount != nil { if m.Histogram.SampleCount != nil {
count := new(model.Sample) count := &model.Sample{
count.Timestamp = timestamp Metric: model.Metric{},
metric := model.Metric{} Value: model.SampleValue(m.Histogram.GetSampleCount()),
Timestamp: timestamp,
}
samples = append(samples, count)
metric := count.Metric
for _, p := range m.Label { for _, p := range m.Label {
metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue()) metric[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
} }
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count") metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
count.Metric = metric
count.Value = model.SampleValue(m.Histogram.GetSampleCount()) if !infSeen {
samples = append(samples, count) 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("le")] = model.LabelValue("+Inf")
metric[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
}
} }
} }

View File

@ -24,6 +24,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"math"
"strings" "strings"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
@ -145,6 +146,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
"expected summary in metric %s", metric, "expected summary in metric %s", metric,
) )
} }
infSeen := false
for _, q := range metric.Histogram.Bucket { for _, q := range metric.Histogram.Bucket {
n, err = writeSample( n, err = writeSample(
name+"_bucket", metric, name+"_bucket", metric,
@ -156,7 +158,21 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
if err != nil { if err != nil {
return written, err return written, err
} }
// TODO: Add +inf bucket if it's missing. if math.IsInf(q.GetUpperBound(), +1) {
infSeen = true
}
}
if !infSeen {
n, err = writeSample(
name+"_bucket", metric,
"le", "+Inf",
float64(metric.Histogram.GetSampleCount()),
out,
)
if err != nil {
return written, err
}
written += n
} }
n, err = writeSample( n, err = writeSample(
name+"_sum", metric, "", "", name+"_sum", metric, "", "",

View File

@ -267,6 +267,50 @@ request_duration_microseconds_bucket{le="172.8"} 1524
request_duration_microseconds_bucket{le="+Inf"} 2693 request_duration_microseconds_bucket{le="+Inf"} 2693
request_duration_microseconds_sum 1.7560473e+06 request_duration_microseconds_sum 1.7560473e+06
request_duration_microseconds_count 2693 request_duration_microseconds_count 2693
`,
},
// 5: Histogram with missing +Inf bucket.
{
in: &dto.MetricFamily{
Name: proto.String("request_duration_microseconds"),
Help: proto.String("The response latency."),
Type: dto.MetricType_HISTOGRAM.Enum(),
Metric: []*dto.Metric{
&dto.Metric{
Histogram: &dto.Histogram{
SampleCount: proto.Uint64(2693),
SampleSum: proto.Float64(1756047.3),
Bucket: []*dto.Bucket{
&dto.Bucket{
UpperBound: proto.Float64(100),
CumulativeCount: proto.Uint64(123),
},
&dto.Bucket{
UpperBound: proto.Float64(120),
CumulativeCount: proto.Uint64(412),
},
&dto.Bucket{
UpperBound: proto.Float64(144),
CumulativeCount: proto.Uint64(592),
},
&dto.Bucket{
UpperBound: proto.Float64(172.8),
CumulativeCount: proto.Uint64(1524),
},
},
},
},
},
},
out: `# 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
`, `,
}, },
} }