Skip to content

Commit

Permalink
Merge pull request prometheus#22 from prometheus/feature/accept-heade…
Browse files Browse the repository at this point in the history
…r-discrimination

WIP — Protocol Buffer negotiation support in handler.
  • Loading branch information
matttproud committed Jul 1, 2013
2 parents 1fb7c8d + 4956aea commit b6cac86
Show file tree
Hide file tree
Showing 18 changed files with 546 additions and 105 deletions.
3 changes: 3 additions & 0 deletions Makefile.TRAVIS
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ preparation:
ln -sf "$(PWD)" $(PROMETHEUS_TARGET)

dependencies:
go get code.google.com/p/goprotobuf/proto
go get github.com/matttproud/gocheck
go get github.com/matttproud/golang_protobuf_extensions/ext
go get github.com/prometheus/client_model/go

test: dependencies preparation
$(MAKE) test
Expand Down
3 changes: 1 addition & 2 deletions extraction/discriminator.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ func ProcessorForRequestHeader(header http.Header) (Processor, error) {
}
switch mediatype {
case "application/vnd.google.protobuf":
// BUG(matt): Version?
if params["proto"] != "io.prometheus.client.MetricFamily" {
return nil, fmt.Errorf("Unrecognized Protocol Message %s", params["proto"])
}
if params["encoding"] != "varint record length-delimited" {
if params["encoding"] != "delimited" {
return nil, fmt.Errorf("Unsupported Encoding %s", params["encoding"])
}
return MetricFamilyProcessor, nil
Expand Down
4 changes: 2 additions & 2 deletions extraction/discriminator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ func testDiscriminatorHttpHeader(t test.Tester) {
err: nil,
},
{
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="varint record length-delimited"`},
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="varint record length-delimited"`},
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`},
output: nil,
err: fmt.Errorf("Unrecognized Protocol Message illegal"),
},
Expand Down
Empty file added foo
Empty file.
4 changes: 3 additions & 1 deletion prometheus/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ const (

// The content type and schema information set on telemetry data responses.
TelemetryContentType = `application/json; schema="prometheus/telemetry"; version=` + APIVersion
// The content type and schema information set on telemetry data responses.
DelimitedTelemetryContentType = `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`

// The customary web services endpoint on which telemetric data is exposed.
ExpositionResource = "/metrics.json"
ExpositionResource = "/metrics"

baseLabelsKey = "baseLabels"
docstringKey = "docstring"
Expand Down
36 changes: 34 additions & 2 deletions prometheus/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
"encoding/json"
"fmt"
"sync"

dto "github.com/prometheus/client_model/go"

"code.google.com/p/goprotobuf/proto"
)

// TODO(matt): Refactor to de-duplicate behaviors.
Expand All @@ -31,13 +35,13 @@ type counterVector struct {

func NewCounter() Counter {
return &counter{
values: map[string]*counterVector{},
values: map[uint64]*counterVector{},
}
}

type counter struct {
mutex sync.RWMutex
values map[string]*counterVector
values map[uint64]*counterVector
}

func (metric *counter) Set(labels map[string]string, value float64) float64 {
Expand Down Expand Up @@ -147,3 +151,31 @@ func (metric *counter) MarshalJSON() ([]byte, error) {
typeKey: counterTypeValue,
})
}

func (metric *counter) dumpChildren(f *dto.MetricFamily) {
metric.mutex.RLock()
defer metric.mutex.RUnlock()

f.Type = dto.MetricType_COUNTER.Enum()

for _, child := range metric.values {
c := &dto.Counter{
Value: proto.Float64(child.Value),
}

m := &dto.Metric{
Counter: c,
}

for name, value := range child.Labels {
p := &dto.LabelPair{
Name: proto.String(name),
Value: proto.String(value),
}

m.Label = append(m.Label, p)
}

f.Metric = append(f.Metric, m)
}
}
36 changes: 34 additions & 2 deletions prometheus/gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
"encoding/json"
"fmt"
"sync"

"code.google.com/p/goprotobuf/proto"

dto "github.com/prometheus/client_model/go"
)

// A gauge metric merely provides an instantaneous representation of a scalar
Expand All @@ -28,13 +32,13 @@ type gaugeVector struct {

func NewGauge() Gauge {
return &gauge{
values: map[string]*gaugeVector{},
values: map[uint64]*gaugeVector{},
}
}

type gauge struct {
mutex sync.RWMutex
values map[string]*gaugeVector
values map[uint64]*gaugeVector
}

func (metric *gauge) String() string {
Expand Down Expand Up @@ -94,3 +98,31 @@ func (metric *gauge) MarshalJSON() ([]byte, error) {
valueKey: values,
})
}

func (metric *gauge) dumpChildren(f *dto.MetricFamily) {
metric.mutex.RLock()
defer metric.mutex.RUnlock()

f.Type = dto.MetricType_GAUGE.Enum()

for _, child := range metric.values {
c := &dto.Gauge{
Value: proto.Float64(child.Value),
}

m := &dto.Metric{
Gauge: c,
}

for name, value := range child.Labels {
p := &dto.LabelPair{
Name: proto.String(name),
Value: proto.String(value),
}

m.Label = append(m.Label, p)
}

f.Metric = append(f.Metric, m)
}
}
49 changes: 44 additions & 5 deletions prometheus/histogram.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import (
"math"
"strconv"
"sync"

dto "github.com/prometheus/client_model/go"

"code.google.com/p/goprotobuf/proto"
)

// This generates count-buckets of equal size distributed along the open
Expand Down Expand Up @@ -75,7 +79,7 @@ type histogram struct {
// These are the buckets that capture samples as they are emitted to the
// histogram. Please consult the reference interface and its implements for
// further details about behavior expectations.
values map[string]*histogramVector
values map[uint64]*histogramVector
// These are the percentile values that will be reported on marshalling.
reportablePercentiles []float64
}
Expand Down Expand Up @@ -157,7 +161,7 @@ func prospectiveIndexForPercentile(percentile float64, totalObservations int) in
}

// Determine the next bucket element when interim bucket intervals may be empty.
func (h histogram) nextNonEmptyBucketElement(signature string, currentIndex, bucketCount int, observationsByBucket []int) (*Bucket, int) {
func (h histogram) nextNonEmptyBucketElement(signature uint64, currentIndex, bucketCount int, observationsByBucket []int) (*Bucket, int) {
for i := currentIndex; i < bucketCount; i++ {
if observationsByBucket[i] == 0 {
continue
Expand All @@ -176,7 +180,7 @@ func (h histogram) nextNonEmptyBucketElement(signature string, currentIndex, buc
// longer contained by the bucket, the index of the last item is returned. This
// may occur if the underlying bucket catalogs values and employs an eviction
// strategy.
func (h histogram) bucketForPercentile(signature string, percentile float64) (*Bucket, int) {
func (h histogram) bucketForPercentile(signature uint64, percentile float64) (*Bucket, int) {
bucketCount := len(h.bucketStarts)

// This captures the quantity of samples in a given bucket's range.
Expand Down Expand Up @@ -229,7 +233,7 @@ func (h histogram) bucketForPercentile(signature string, percentile float64) (*B
// Return the histogram's estimate of the value for a given percentile of
// collected samples. The requested percentile is expected to be a real
// value within (0, 1.0].
func (h histogram) percentile(signature string, percentile float64) float64 {
func (h histogram) percentile(signature uint64, percentile float64) float64 {
bucket, index := h.bucketForPercentile(signature, percentile)

return (*bucket).ValueForIndex(index)
Expand Down Expand Up @@ -284,7 +288,7 @@ func NewHistogram(specification *HistogramSpecification) Histogram {
bucketMaker: specification.BucketBuilder,
bucketStarts: specification.Starts,
reportablePercentiles: specification.ReportablePercentiles,
values: map[string]*histogramVector{},
values: map[uint64]*histogramVector{},
}

return metric
Expand All @@ -301,3 +305,38 @@ func NewDefaultHistogram() Histogram {
},
)
}

func (metric *histogram) dumpChildren(f *dto.MetricFamily) {
metric.mutex.RLock()
defer metric.mutex.RUnlock()

f.Type = dto.MetricType_SUMMARY.Enum()

for signature, child := range metric.values {
c := &dto.Summary{}

m := &dto.Metric{
Summary: c,
}

for name, value := range child.labels {
p := &dto.LabelPair{
Name: proto.String(name),
Value: proto.String(value),
}

m.Label = append(m.Label, p)
}

for _, percentile := range metric.reportablePercentiles {
q := &dto.Quantile{
Quantile: proto.Float64(percentile),
Value: proto.Float64(metric.percentile(signature, percentile)),
}

c.Quantile = append(c.Quantile, q)
}

f.Metric = append(f.Metric, m)
}
}
8 changes: 7 additions & 1 deletion prometheus/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@

package prometheus

import "encoding/json"
import (
"encoding/json"

dto "github.com/prometheus/client_model/go"
)

// A Metric is something that can be exposed via the registry framework.
type Metric interface {
Expand All @@ -16,4 +20,6 @@ type Metric interface {
ResetAll()
// Produce a human-consumable representation of the metric.
String() string
// dumpChildren populates the child metrics of the given family.
dumpChildren(*dto.MetricFamily)
}
Loading

0 comments on commit b6cac86

Please sign in to comment.