Eliminate a number of style-guide violations.
Change-Id: Iedcd611e5c7ad24c84c004d8d6c551d1734e443c
This commit is contained in:
parent
00816363e4
commit
9da2fbcce3
14
README.md
14
README.md
|
@ -80,3 +80,17 @@ ensure that all tests pass by running the following from the project root:
|
||||||
|
|
||||||
The use of gocheck is summarily being phased out; however, old tests that use it
|
The use of gocheck is summarily being phased out; however, old tests that use it
|
||||||
still exist.
|
still exist.
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Same as for the `prometheus/prometheus` repository, we are using
|
||||||
|
Gerrit to manage reviews of pull-requests for this repository. See
|
||||||
|
[`CONTRIBUTING.md`](https://github.com/prometheus/prometheus/blob/master/CONTRIBUTING.md)
|
||||||
|
in the `prometheus/prometheus` repository for details (but replace the
|
||||||
|
`prometheus` repository name by `client_golang`).
|
||||||
|
|
||||||
|
Please try to avoid warnings flagged by [`go
|
||||||
|
vet`](https://godoc.org/code.google.com/p/go.tools/cmd/vet) and by
|
||||||
|
[`golint`](https://github.com/golang/lint), and pay attention to the
|
||||||
|
[Go Code Review
|
||||||
|
Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments).
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
package extraction
|
package extraction
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -24,20 +25,20 @@ import (
|
||||||
// Processor can be found, an error is returned.
|
// Processor can be found, an error is returned.
|
||||||
func ProcessorForRequestHeader(header http.Header) (Processor, error) {
|
func ProcessorForRequestHeader(header http.Header) (Processor, error) {
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, fmt.Errorf("Received illegal and nil header.")
|
return nil, errors.New("received illegal and nil header")
|
||||||
}
|
}
|
||||||
|
|
||||||
mediatype, params, err := mime.ParseMediaType(header.Get("Content-Type"))
|
mediatype, params, err := mime.ParseMediaType(header.Get("Content-Type"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Invalid Content-Type header %q: %s", header.Get("Content-Type"), err)
|
return nil, fmt.Errorf("invalid Content-Type header %q: %s", header.Get("Content-Type"), err)
|
||||||
}
|
}
|
||||||
switch mediatype {
|
switch mediatype {
|
||||||
case "application/vnd.google.protobuf":
|
case "application/vnd.google.protobuf":
|
||||||
if params["proto"] != "io.prometheus.client.MetricFamily" {
|
if params["proto"] != "io.prometheus.client.MetricFamily" {
|
||||||
return nil, fmt.Errorf("Unrecognized Protocol Message %s", params["proto"])
|
return nil, fmt.Errorf("unrecognized protocol message %s", params["proto"])
|
||||||
}
|
}
|
||||||
if params["encoding"] != "delimited" {
|
if params["encoding"] != "delimited" {
|
||||||
return nil, fmt.Errorf("Unsupported Encoding %s", params["encoding"])
|
return nil, fmt.Errorf("unsupported encoding %s", params["encoding"])
|
||||||
}
|
}
|
||||||
return MetricFamilyProcessor, nil
|
return MetricFamilyProcessor, nil
|
||||||
case "text/plain":
|
case "text/plain":
|
||||||
|
@ -48,26 +49,26 @@ func ProcessorForRequestHeader(header http.Header) (Processor, error) {
|
||||||
// Fallback: most recent version.
|
// Fallback: most recent version.
|
||||||
return Processor004, nil
|
return Processor004, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unrecognized API version %s", params["version"])
|
return nil, fmt.Errorf("unrecognized API version %s", params["version"])
|
||||||
}
|
}
|
||||||
case "application/json":
|
case "application/json":
|
||||||
var prometheusApiVersion string
|
var prometheusAPIVersion string
|
||||||
|
|
||||||
if params["schema"] == "prometheus/telemetry" && params["version"] != "" {
|
if params["schema"] == "prometheus/telemetry" && params["version"] != "" {
|
||||||
prometheusApiVersion = params["version"]
|
prometheusAPIVersion = params["version"]
|
||||||
} else {
|
} else {
|
||||||
prometheusApiVersion = header.Get("X-Prometheus-API-Version")
|
prometheusAPIVersion = header.Get("X-Prometheus-API-Version")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch prometheusApiVersion {
|
switch prometheusAPIVersion {
|
||||||
case "0.0.2":
|
case "0.0.2":
|
||||||
return Processor002, nil
|
return Processor002, nil
|
||||||
case "0.0.1":
|
case "0.0.1":
|
||||||
return Processor001, nil
|
return Processor001, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unrecognized API version %s", prometheusApiVersion)
|
return nil, fmt.Errorf("unrecognized API version %s", prometheusAPIVersion)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unsupported media type %q, expected %q", mediatype, "application/json")
|
return nil, fmt.Errorf("unsupported media type %q, expected %q", mediatype, "application/json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,14 @@
|
||||||
package extraction
|
package extraction
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/test"
|
"github.com/prometheus/client_golang/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testDiscriminatorHttpHeader(t test.Tester) {
|
func testDiscriminatorHTTPHeader(t test.Tester) {
|
||||||
var scenarios = []struct {
|
var scenarios = []struct {
|
||||||
input map[string]string
|
input map[string]string
|
||||||
output Processor
|
output Processor
|
||||||
|
@ -29,12 +29,12 @@ func testDiscriminatorHttpHeader(t test.Tester) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
output: nil,
|
output: nil,
|
||||||
err: fmt.Errorf("Received illegal and nil header."),
|
err: errors.New("received illegal and nil header"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: map[string]string{"Content-Type": "application/json", "X-Prometheus-API-Version": "0.0.0"},
|
input: map[string]string{"Content-Type": "application/json", "X-Prometheus-API-Version": "0.0.0"},
|
||||||
output: nil,
|
output: nil,
|
||||||
err: fmt.Errorf("Unrecognized API version 0.0.0"),
|
err: errors.New("unrecognized API version 0.0.0"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: map[string]string{"Content-Type": "application/json", "X-Prometheus-API-Version": "0.0.1"},
|
input: map[string]string{"Content-Type": "application/json", "X-Prometheus-API-Version": "0.0.1"},
|
||||||
|
@ -44,7 +44,7 @@ func testDiscriminatorHttpHeader(t test.Tester) {
|
||||||
{
|
{
|
||||||
input: map[string]string{"Content-Type": `application/json; schema="prometheus/telemetry"; version=0.0.0`},
|
input: map[string]string{"Content-Type": `application/json; schema="prometheus/telemetry"; version=0.0.0`},
|
||||||
output: nil,
|
output: nil,
|
||||||
err: fmt.Errorf("Unrecognized API version 0.0.0"),
|
err: errors.New("unrecognized API version 0.0.0"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: map[string]string{"Content-Type": `application/json; schema="prometheus/telemetry"; version=0.0.1`},
|
input: map[string]string{"Content-Type": `application/json; schema="prometheus/telemetry"; version=0.0.1`},
|
||||||
|
@ -64,12 +64,12 @@ func testDiscriminatorHttpHeader(t test.Tester) {
|
||||||
{
|
{
|
||||||
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`},
|
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`},
|
||||||
output: nil,
|
output: nil,
|
||||||
err: fmt.Errorf("Unrecognized Protocol Message illegal"),
|
err: errors.New("unrecognized protocol message illegal"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`},
|
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`},
|
||||||
output: nil,
|
output: nil,
|
||||||
err: fmt.Errorf("Unsupported Encoding illegal"),
|
err: errors.New("unsupported encoding illegal"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: map[string]string{"Content-Type": `text/plain; version=0.0.4`},
|
input: map[string]string{"Content-Type": `text/plain; version=0.0.4`},
|
||||||
|
@ -84,7 +84,7 @@ func testDiscriminatorHttpHeader(t test.Tester) {
|
||||||
{
|
{
|
||||||
input: map[string]string{"Content-Type": `text/plain; version=0.0.3`},
|
input: map[string]string{"Content-Type": `text/plain; version=0.0.3`},
|
||||||
output: nil,
|
output: nil,
|
||||||
err: fmt.Errorf("Unrecognized API version 0.0.3"),
|
err: errors.New("unrecognized API version 0.0.3"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,12 +117,12 @@ func testDiscriminatorHttpHeader(t test.Tester) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDiscriminatorHttpHeader(t *testing.T) {
|
func TestDiscriminatorHTTPHeader(t *testing.T) {
|
||||||
testDiscriminatorHttpHeader(t)
|
testDiscriminatorHTTPHeader(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkDiscriminatorHttpHeader(b *testing.B) {
|
func BenchmarkDiscriminatorHTTPHeader(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
testDiscriminatorHttpHeader(b)
|
testDiscriminatorHTTPHeader(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,9 @@ const (
|
||||||
percentile001 = "percentile"
|
percentile001 = "percentile"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Processor002 is responsible for decoding payloads from protocol version
|
// Processor001 is responsible for decoding payloads from protocol version
|
||||||
// 0.0.1.
|
// 0.0.1.
|
||||||
var Processor001 Processor = &processor001{}
|
var Processor001 = &processor001{}
|
||||||
|
|
||||||
// processor001 is responsible for handling API version 0.0.1.
|
// processor001 is responsible for handling API version 0.0.1.
|
||||||
type processor001 struct{}
|
type processor001 struct{}
|
||||||
|
@ -77,7 +77,7 @@ func (p *processor001) ProcessSingle(in io.Reader, out Ingester, o *ProcessOptio
|
||||||
case gauge001, counter001:
|
case gauge001, counter001:
|
||||||
sampleValue, ok := value.Value.(float64)
|
sampleValue, ok := value.Value.(float64)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = fmt.Errorf("Could not convert value from %s %s to float64.", entity, value)
|
err = fmt.Errorf("could not convert value from %s %s to float64", entity, value)
|
||||||
if err := out.Ingest(&Result{Err: err}); err != nil {
|
if err := out.Ingest(&Result{Err: err}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ func (p *processor001) ProcessSingle(in io.Reader, out Ingester, o *ProcessOptio
|
||||||
case histogram001:
|
case histogram001:
|
||||||
sampleValue, ok := value.Value.(map[string]interface{})
|
sampleValue, ok := value.Value.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
err = fmt.Errorf("Could not convert value from %q to a map[string]interface{}.", value.Value)
|
err = fmt.Errorf("could not convert value from %q to a map[string]interface{}", value.Value)
|
||||||
if err := out.Ingest(&Result{Err: err}); err != nil {
|
if err := out.Ingest(&Result{Err: err}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func (p *processor001) ProcessSingle(in io.Reader, out Ingester, o *ProcessOptio
|
||||||
for percentile, percentileValue := range sampleValue {
|
for percentile, percentileValue := range sampleValue {
|
||||||
individualValue, ok := percentileValue.(float64)
|
individualValue, ok := percentileValue.(float64)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = fmt.Errorf("Could not convert value from %q to a float64.", percentileValue)
|
err = fmt.Errorf("could not convert value from %q to a float64", percentileValue)
|
||||||
if err := out.Ingest(&Result{Err: err}); err != nil {
|
if err := out.Ingest(&Result{Err: err}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
package extraction
|
package extraction
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -68,7 +68,7 @@ func testProcessor001Process(t test.Tester) {
|
||||||
var scenarios = []testProcessor001ProcessScenario{
|
var scenarios = []testProcessor001ProcessScenario{
|
||||||
{
|
{
|
||||||
in: "empty.json",
|
in: "empty.json",
|
||||||
err: fmt.Errorf("unexpected end of JSON input"),
|
err: errors.New("unexpected end of JSON input"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: "test0_0_1-0_0_2.json",
|
in: "test0_0_1-0_0_2.json",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
|
|
||||||
// Processor002 is responsible for decoding payloads from protocol version
|
// Processor002 is responsible for decoding payloads from protocol version
|
||||||
// 0.0.2.
|
// 0.0.2.
|
||||||
var Processor002 = new(processor002)
|
var Processor002 = &processor002{}
|
||||||
|
|
||||||
type histogram002 struct {
|
type histogram002 struct {
|
||||||
Labels map[string]string `json:"labels"`
|
Labels map[string]string `json:"labels"`
|
||||||
|
@ -60,7 +60,7 @@ func (p *processor002) ProcessSingle(in io.Reader, out Ingester, o *ProcessOptio
|
||||||
var values []counter002
|
var values []counter002
|
||||||
|
|
||||||
if err := json.Unmarshal(entity.Metric.Values, &values); err != nil {
|
if err := json.Unmarshal(entity.Metric.Values, &values); err != nil {
|
||||||
err := fmt.Errorf("Could not extract %s value: %s", entity.Metric.Type, err)
|
err := fmt.Errorf("could not extract %s value: %s", entity.Metric.Type, err)
|
||||||
if err := out.Ingest(&Result{Err: err}); err != nil {
|
if err := out.Ingest(&Result{Err: err}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ func (p *processor002) ProcessSingle(in io.Reader, out Ingester, o *ProcessOptio
|
||||||
var values []histogram002
|
var values []histogram002
|
||||||
|
|
||||||
if err := json.Unmarshal(entity.Metric.Values, &values); err != nil {
|
if err := json.Unmarshal(entity.Metric.Values, &values); err != nil {
|
||||||
err := fmt.Errorf("Could not extract %s value: %s", entity.Metric.Type, err)
|
err := fmt.Errorf("could not extract %s value: %s", entity.Metric.Type, err)
|
||||||
if err := out.Ingest(&Result{Err: err}); err != nil {
|
if err := out.Ingest(&Result{Err: err}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ func (p *processor002) ProcessSingle(in io.Reader, out Ingester, o *ProcessOptio
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("Unknown metric type %q", entity.Metric.Type)
|
err := fmt.Errorf("unknown metric type %q", entity.Metric.Type)
|
||||||
if err := out.Ingest(&Result{Err: err}); err != nil {
|
if err := out.Ingest(&Result{Err: err}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
package extraction
|
package extraction
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -69,7 +69,7 @@ func testProcessor002Process(t test.Tester) {
|
||||||
var scenarios = []testProcessor002ProcessScenario{
|
var scenarios = []testProcessor002ProcessScenario{
|
||||||
{
|
{
|
||||||
in: "empty.json",
|
in: "empty.json",
|
||||||
err: fmt.Errorf("EOF"),
|
err: errors.New("EOF"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: "test0_0_1-0_0_2.json",
|
in: "test0_0_1-0_0_2.json",
|
||||||
|
|
|
@ -36,6 +36,8 @@ func (f *Fingerprint) String() string {
|
||||||
return strings.Join([]string{fmt.Sprintf("%020d", f.Hash), f.FirstCharacterOfFirstLabelName, fmt.Sprint(f.LabelMatterLength), f.LastCharacterOfLastLabelValue}, "-")
|
return strings.Join([]string{fmt.Sprintf("%020d", f.Hash), f.FirstCharacterOfFirstLabelName, fmt.Sprint(f.LabelMatterLength), f.LastCharacterOfLastLabelValue}, "-")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Less compares first the Hash, then the FirstCharacterOfFirstLabelName, then
|
||||||
|
// the LabelMatterLength, then the LastCharacterOfLastLabelValue.
|
||||||
func (f *Fingerprint) Less(o *Fingerprint) bool {
|
func (f *Fingerprint) Less(o *Fingerprint) bool {
|
||||||
if f.Hash < o.Hash {
|
if f.Hash < o.Hash {
|
||||||
return true
|
return true
|
||||||
|
@ -67,6 +69,7 @@ func (f *Fingerprint) Less(o *Fingerprint) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equal uses the same semantics as Less.
|
||||||
func (f *Fingerprint) Equal(o *Fingerprint) bool {
|
func (f *Fingerprint) Equal(o *Fingerprint) bool {
|
||||||
if f.Hash != o.Hash {
|
if f.Hash != o.Hash {
|
||||||
return false
|
return false
|
||||||
|
@ -146,8 +149,8 @@ func (f *Fingerprint) LoadFromMetric(m Metric) {
|
||||||
f.LastCharacterOfLastLabelValue = lastCharacterOfLastLabelValue
|
f.LastCharacterOfLastLabelValue = lastCharacterOfLastLabelValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents a collection of Fingerprint subject to a given natural sorting
|
// Fingerprints represents a collection of Fingerprint subject to a given
|
||||||
// scheme.
|
// natural sorting scheme. It implements sort.Interface.
|
||||||
type Fingerprints []*Fingerprint
|
type Fingerprints []*Fingerprint
|
||||||
|
|
||||||
func (f Fingerprints) Len() int {
|
func (f Fingerprints) Len() int {
|
||||||
|
@ -162,8 +165,10 @@ func (f Fingerprints) Swap(i, j int) {
|
||||||
f[i], f[j] = f[j], f[i]
|
f[i], f[j] = f[j], f[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
type FingerprintSet map[Fingerprint]bool
|
// FingerprintSet is a set of Fingerprints.
|
||||||
|
type FingerprintSet map[Fingerprint]struct{}
|
||||||
|
|
||||||
|
// Equal returns true if both sets contain the same elements (and not more).
|
||||||
func (s FingerprintSet) Equal(o FingerprintSet) bool {
|
func (s FingerprintSet) Equal(o FingerprintSet) bool {
|
||||||
if len(s) != len(o) {
|
if len(s) != len(o) {
|
||||||
return false
|
return false
|
||||||
|
@ -178,6 +183,7 @@ func (s FingerprintSet) Equal(o FingerprintSet) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Intersection returns the elements contained in both sets.
|
||||||
func (s FingerprintSet) Intersection(o FingerprintSet) FingerprintSet {
|
func (s FingerprintSet) Intersection(o FingerprintSet) FingerprintSet {
|
||||||
myLength, otherLength := len(s), len(o)
|
myLength, otherLength := len(s), len(o)
|
||||||
if myLength == 0 || otherLength == 0 {
|
if myLength == 0 || otherLength == 0 {
|
||||||
|
@ -196,7 +202,7 @@ func (s FingerprintSet) Intersection(o FingerprintSet) FingerprintSet {
|
||||||
|
|
||||||
for k := range subSet {
|
for k := range subSet {
|
||||||
if _, ok := superSet[k]; ok {
|
if _, ok := superSet[k]; ok {
|
||||||
out[k] = true
|
out[k] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,18 +18,20 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// The label name prefix to prepend if a synthetic label is already present
|
// ExporterLabelPrefix is the label name prefix to prepend if a
|
||||||
// in the exported metrics.
|
// synthetic label is already present in the exported metrics.
|
||||||
ExporterLabelPrefix LabelName = "exporter_"
|
ExporterLabelPrefix LabelName = "exporter_"
|
||||||
|
|
||||||
// The label name indicating the metric name of a timeseries.
|
// MetricNameLabel is the label name indicating the metric name of a
|
||||||
|
// timeseries.
|
||||||
MetricNameLabel LabelName = "__name__"
|
MetricNameLabel LabelName = "__name__"
|
||||||
|
|
||||||
// ReservedLabelPrefix is a prefix which is not legal in user-supplied label
|
// ReservedLabelPrefix is a prefix which is not legal in user-supplied
|
||||||
// names.
|
// label names.
|
||||||
ReservedLabelPrefix = "__"
|
ReservedLabelPrefix = "__"
|
||||||
|
|
||||||
// The label name indicating the job from which a timeseries was scraped.
|
// JobLabel is the label name indicating the job from which a timeseries
|
||||||
|
// was scraped.
|
||||||
JobLabel LabelName = "job"
|
JobLabel LabelName = "job"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,6 +39,7 @@ const (
|
||||||
// therewith.
|
// therewith.
|
||||||
type LabelName string
|
type LabelName string
|
||||||
|
|
||||||
|
// LabelNames is a sortable LabelName slice. In implements sort.Interface.
|
||||||
type LabelNames []LabelName
|
type LabelNames []LabelName
|
||||||
|
|
||||||
func (l LabelNames) Len() int {
|
func (l LabelNames) Len() int {
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
// match.
|
// match.
|
||||||
type LabelSet map[LabelName]LabelValue
|
type LabelSet map[LabelName]LabelValue
|
||||||
|
|
||||||
// Helper function to non-destructively merge two label sets.
|
// Merge is a helper function to non-destructively merge two label sets.
|
||||||
func (l LabelSet) Merge(other LabelSet) LabelSet {
|
func (l LabelSet) Merge(other LabelSet) LabelSet {
|
||||||
result := make(LabelSet, len(l))
|
result := make(LabelSet, len(l))
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ func (l LabelSet) String() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MergeFromMetric merges Metric into this LabelSet.
|
||||||
func (l LabelSet) MergeFromMetric(m Metric) {
|
func (l LabelSet) MergeFromMetric(m Metric) {
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
l[k] = v
|
l[k] = v
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
// A LabelValue is an associated value for a LabelName.
|
// A LabelValue is an associated value for a LabelName.
|
||||||
type LabelValue string
|
type LabelValue string
|
||||||
|
|
||||||
|
// LabelValues is a sortable LabelValue slice. It implements sort.Interface.
|
||||||
type LabelValues []LabelValue
|
type LabelValues []LabelValue
|
||||||
|
|
||||||
func (l LabelValues) Len() int {
|
func (l LabelValues) Len() int {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
// 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 map[LabelName]LabelValue
|
||||||
|
|
||||||
|
// Equal compares the fingerprints of both metrics.
|
||||||
func (m Metric) Equal(o Metric) bool {
|
func (m Metric) Equal(o Metric) bool {
|
||||||
lFingerprint := &Fingerprint{}
|
lFingerprint := &Fingerprint{}
|
||||||
rFingerprint := &Fingerprint{}
|
rFingerprint := &Fingerprint{}
|
||||||
|
@ -33,6 +34,7 @@ func (m Metric) Equal(o Metric) bool {
|
||||||
return lFingerprint.Equal(rFingerprint)
|
return lFingerprint.Equal(rFingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Before compares the fingerprints of both metrics.
|
||||||
func (m Metric) Before(o Metric) bool {
|
func (m Metric) Before(o Metric) bool {
|
||||||
lFingerprint := &Fingerprint{}
|
lFingerprint := &Fingerprint{}
|
||||||
rFingerprint := &Fingerprint{}
|
rFingerprint := &Fingerprint{}
|
||||||
|
@ -64,6 +66,8 @@ func (m Metric) String() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
func (m Metric) MergeFromLabelSet(labels LabelSet, collisionPrefix LabelName) {
|
||||||
for k, v := range labels {
|
for k, v := range labels {
|
||||||
if collisionPrefix != "" {
|
if collisionPrefix != "" {
|
||||||
|
|
|
@ -13,12 +13,14 @@
|
||||||
|
|
||||||
package model
|
package model
|
||||||
|
|
||||||
|
// Sample is a sample value with a timestamp and a metric.
|
||||||
type Sample struct {
|
type Sample struct {
|
||||||
Metric Metric
|
Metric Metric
|
||||||
Value SampleValue
|
Value SampleValue
|
||||||
Timestamp Timestamp
|
Timestamp Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equal compares first the metrics, then the timestamp, then the value.
|
||||||
func (s *Sample) Equal(o *Sample) bool {
|
func (s *Sample) Equal(o *Sample) bool {
|
||||||
if s == o {
|
if s == o {
|
||||||
return true
|
return true
|
||||||
|
@ -37,12 +39,14 @@ func (s *Sample) Equal(o *Sample) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Samples is a sortable Sample slice. It implements sort.Interface.
|
||||||
type Samples []*Sample
|
type Samples []*Sample
|
||||||
|
|
||||||
func (s Samples) Len() int {
|
func (s Samples) Len() int {
|
||||||
return len(s)
|
return len(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Less compares first the metrics, then the timestamp.
|
||||||
func (s Samples) Less(i, j int) bool {
|
func (s Samples) Less(i, j int) bool {
|
||||||
switch {
|
switch {
|
||||||
case s[i].Metric.Before(s[j].Metric):
|
case s[i].Metric.Before(s[j].Metric):
|
||||||
|
|
|
@ -21,10 +21,12 @@ import (
|
||||||
// time.
|
// time.
|
||||||
type SampleValue float64
|
type SampleValue float64
|
||||||
|
|
||||||
|
// Equal does a straight v==o.
|
||||||
func (v SampleValue) Equal(o SampleValue) bool {
|
func (v SampleValue) Equal(o SampleValue) bool {
|
||||||
return v == o
|
return v == o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
func (v SampleValue) MarshalJSON() ([]byte, error) {
|
func (v SampleValue) MarshalJSON() ([]byte, error) {
|
||||||
return []byte(fmt.Sprintf(`"%f"`, v)), nil
|
return []byte(fmt.Sprintf(`"%f"`, v)), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,15 @@ import (
|
||||||
// methods below, so it will be easy to change this later
|
// methods below, so it will be easy to change this later
|
||||||
// without requiring significant user code changes.
|
// without requiring significant user code changes.
|
||||||
|
|
||||||
// Time in seconds since the epoch (January 1, 1970 UTC).
|
// Timestamp is the number of seconds since the epoch (1970-01-01 00:00 UTC)
|
||||||
|
// without leap seconds.
|
||||||
type Timestamp int64
|
type Timestamp int64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// The minimum supported time resolution. This has to be at least
|
// MinimumTick is the minimum supported time resolution. This has to be
|
||||||
// native_time.Second in order for the code below to work.
|
// at least native_time.Second in order for the code below to work.
|
||||||
MinimumTick = native_time.Second
|
MinimumTick = native_time.Second
|
||||||
// The timestamp duration equivalent to one second.
|
// second is the timestamp duration equivalent to one second.
|
||||||
second = int64(native_time.Second / MinimumTick)
|
second = int64(native_time.Second / MinimumTick)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ func (t Timestamp) Before(o Timestamp) bool {
|
||||||
return t < o
|
return t < o
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before reports whether the timestamp t is after o.
|
// After reports whether the timestamp t is after o.
|
||||||
func (t Timestamp) After(o Timestamp) bool {
|
func (t Timestamp) After(o Timestamp) bool {
|
||||||
return t > o
|
return t > o
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,12 +72,12 @@ func TestDuration(t *testing.T) {
|
||||||
|
|
||||||
ts := TimestampFromTime(goTime)
|
ts := TimestampFromTime(goTime)
|
||||||
if !goTime.Add(duration).Equal(ts.Add(duration).Time()) {
|
if !goTime.Add(duration).Equal(ts.Add(duration).Time()) {
|
||||||
t.Fatalf("%d. 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))
|
||||||
}
|
}
|
||||||
|
|
||||||
earlier := ts.Add(-duration)
|
earlier := ts.Add(-duration)
|
||||||
delta := ts.Sub(earlier)
|
delta := ts.Sub(earlier)
|
||||||
if delta != duration {
|
if delta != duration {
|
||||||
t.Fatalf("%d. Expected %s to be equal to %s", delta, duration)
|
t.Fatalf("Expected %s to be equal to %s", delta, duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,30 +8,35 @@ package prometheus
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// NilLabels is a nil set of labels merely for end-user convenience.
|
// NilLabels is a nil set of labels merely for end-user convenience.
|
||||||
NilLabels map[string]string = nil
|
NilLabels map[string]string
|
||||||
|
|
||||||
// The default http.Handler for exposing telemetric data over a web services
|
// DefaultHandler is the default http.Handler for exposing telemetric
|
||||||
// interface.
|
// data over a web services interface.
|
||||||
DefaultHandler = DefaultRegistry.Handler()
|
DefaultHandler = DefaultRegistry.Handler()
|
||||||
|
|
||||||
// This is the default registry with which Metric objects are associated.
|
// DefaultRegistry with which Metric objects are associated.
|
||||||
DefaultRegistry = NewRegistry()
|
DefaultRegistry = NewRegistry()
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// A prefix to be used to namespace instrumentation flags from others.
|
// FlagNamespace is a prefix to be used to namespace instrumentation
|
||||||
|
// flags from others.
|
||||||
FlagNamespace = "telemetry."
|
FlagNamespace = "telemetry."
|
||||||
|
|
||||||
// The format of the exported data. This will match this library's version,
|
// APIVersion is the version of the format of the exported data. This
|
||||||
// which subscribes to the Semantic Versioning scheme.
|
// will match this library's version, which subscribes to the Semantic
|
||||||
|
// Versioning scheme.
|
||||||
APIVersion = "0.0.2"
|
APIVersion = "0.0.2"
|
||||||
|
|
||||||
// The content type and schema information set on telemetry data responses.
|
// TelemetryContentType is the content type and schema information set
|
||||||
|
// on telemetry data responses.
|
||||||
TelemetryContentType = `application/json; schema="prometheus/telemetry"; version=` + APIVersion
|
TelemetryContentType = `application/json; schema="prometheus/telemetry"; version=` + APIVersion
|
||||||
// The content type and schema information set on telemetry data responses.
|
// DelimitedTelemetryContentType is the content type and schema
|
||||||
|
// information set on telemetry data responses.
|
||||||
DelimitedTelemetryContentType = `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`
|
DelimitedTelemetryContentType = `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`
|
||||||
|
|
||||||
// The customary web services endpoint on which telemetric data is exposed.
|
// ExpositionResource is the customary web services endpoint on which
|
||||||
|
// telemetric data is exposed.
|
||||||
ExpositionResource = "/metrics"
|
ExpositionResource = "/metrics"
|
||||||
|
|
||||||
baseLabelsKey = "baseLabels"
|
baseLabelsKey = "baseLabels"
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "github.com/matttproud/gocheck"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
. "github.com/matttproud/gocheck"
|
||||||
)
|
)
|
||||||
|
|
||||||
type isNaNChecker struct {
|
type isNaNChecker struct {
|
||||||
|
@ -18,7 +19,7 @@ type isNaNChecker struct {
|
||||||
|
|
||||||
// This piece provides a simple tester for the gocheck testing library to
|
// This piece provides a simple tester for the gocheck testing library to
|
||||||
// ascertain if a value is not-a-number.
|
// ascertain if a value is not-a-number.
|
||||||
var IsNaN Checker = &isNaNChecker{
|
var IsNaN = &isNaNChecker{
|
||||||
&CheckerInfo{Name: "IsNaN", Params: []string{"value"}},
|
&CheckerInfo{Name: "IsNaN", Params: []string{"value"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ type valueEqualsChecker struct {
|
||||||
*CheckerInfo
|
*CheckerInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
var ValueEquals Checker = &valueEqualsChecker{
|
var ValueEquals = &valueEqualsChecker{
|
||||||
&CheckerInfo{Name: "IsValue", Params: []string{"obtained", "expected"}},
|
&CheckerInfo{Name: "IsValue", Params: []string{"obtained", "expected"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,15 +98,15 @@ type Registry interface {
|
||||||
YieldExporter() http.HandlerFunc
|
YieldExporter() http.HandlerFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// This builds a new metric registry. It is not needed in the majority of
|
// NewRegistry builds a new metric registry. It is not needed in the majority
|
||||||
// cases.
|
// of cases.
|
||||||
func NewRegistry() Registry {
|
func NewRegistry() Registry {
|
||||||
return ®istry{
|
return ®istry{
|
||||||
signatureContainers: make(map[uint64]*container),
|
signatureContainers: make(map[uint64]*container),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Associate a Metric with the DefaultRegistry.
|
// Register associates a Metric with the DefaultRegistry.
|
||||||
func Register(name, docstring string, baseLabels map[string]string, metric Metric) error {
|
func Register(name, docstring string, baseLabels map[string]string, metric Metric) error {
|
||||||
return DefaultRegistry.Register(name, docstring, baseLabels, metric)
|
return DefaultRegistry.Register(name, docstring, baseLabels, metric)
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ func (r *registry) SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily)
|
||||||
r.metricFamilyInjectionHook = hook
|
r.metricFamilyInjectionHook = hook
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements json.Marshaler
|
// MarshalJSON implements json.Marshaler.
|
||||||
func (r *registry) MarshalJSON() ([]byte, error) {
|
func (r *registry) MarshalJSON() ([]byte, error) {
|
||||||
containers := make(containers, 0, len(r.signatureContainers))
|
containers := make(containers, 0, len(r.signatureContainers))
|
||||||
|
|
||||||
|
@ -218,12 +218,12 @@ func (r *registry) Register(name, docstring string, baseLabels map[string]string
|
||||||
|
|
||||||
// YieldBasicAuthExporter creates a http.HandlerFunc that is protected by HTTP's
|
// YieldBasicAuthExporter creates a http.HandlerFunc that is protected by HTTP's
|
||||||
// basic authentication.
|
// basic authentication.
|
||||||
func (register *registry) YieldBasicAuthExporter(username, password string) http.HandlerFunc {
|
func (r *registry) YieldBasicAuthExporter(username, password string) http.HandlerFunc {
|
||||||
// XXX: Work with Daniel to get this removed from the library, as it is really
|
// XXX: Work with Daniel to get this removed from the library, as it is really
|
||||||
// superfluous and can be much more elegantly accomplished via
|
// superfluous and can be much more elegantly accomplished via
|
||||||
// delegation.
|
// delegation.
|
||||||
log.Println("Registry.YieldBasicAuthExporter is deprecated.")
|
log.Println("Registry.YieldBasicAuthExporter is deprecated.")
|
||||||
exporter := register.YieldExporter()
|
exporter := r.YieldExporter()
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
authenticated := false
|
authenticated := false
|
||||||
|
@ -261,10 +261,10 @@ func decorateWriter(request *http.Request, writer http.ResponseWriter) io.Writer
|
||||||
return gziper
|
return gziper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (registry *registry) YieldExporter() http.HandlerFunc {
|
func (r *registry) YieldExporter() http.HandlerFunc {
|
||||||
log.Println("Registry.YieldExporter is deprecated in favor of Registry.Handler.")
|
log.Println("Registry.YieldExporter is deprecated in favor of Registry.Handler.")
|
||||||
|
|
||||||
return registry.Handler()
|
return r.Handler()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registry) dumpDelimitedPB(w io.Writer) {
|
func (r *registry) dumpDelimitedPB(w io.Writer) {
|
||||||
|
@ -311,20 +311,20 @@ func (r *registry) dumpDelimitedExternalPB(w io.Writer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (registry *registry) Handler() http.HandlerFunc {
|
func (r *registry) Handler() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
defer requestLatencyAccumulator(time.Now())
|
defer requestLatencyAccumulator(time.Now())
|
||||||
|
|
||||||
requestCount.Increment(nil)
|
requestCount.Increment(nil)
|
||||||
header := w.Header()
|
header := w.Header()
|
||||||
|
|
||||||
writer := decorateWriter(r, w)
|
writer := decorateWriter(req, w)
|
||||||
|
|
||||||
if closer, ok := writer.(io.Closer); ok {
|
if closer, ok := writer.(io.Closer); ok {
|
||||||
defer closer.Close()
|
defer closer.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
accepts := goautoneg.ParseAccept(r.Header.Get("Accept"))
|
accepts := goautoneg.ParseAccept(req.Header.Get("Accept"))
|
||||||
for _, accept := range accepts {
|
for _, accept := range accepts {
|
||||||
if accept.Type != "application" {
|
if accept.Type != "application" {
|
||||||
continue
|
continue
|
||||||
|
@ -339,14 +339,14 @@ func (registry *registry) Handler() http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
header.Set(contentTypeHeader, DelimitedTelemetryContentType)
|
header.Set(contentTypeHeader, DelimitedTelemetryContentType)
|
||||||
registry.dumpDelimitedPB(writer)
|
r.dumpDelimitedPB(writer)
|
||||||
registry.dumpDelimitedExternalPB(writer)
|
r.dumpDelimitedExternalPB(writer)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header.Set(contentTypeHeader, TelemetryContentType)
|
header.Set(contentTypeHeader, TelemetryContentType)
|
||||||
json.NewEncoder(writer).Encode(registry)
|
json.NewEncoder(writer).Encode(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue