[VOL-4290] Voltha go library updates for gRPC migration
Change-Id: I1aa2774beb6b7ed7419bc45aeb53fcae8a8ecda0
diff --git a/vendor/github.com/prometheus/common/expfmt/decode.go b/vendor/github.com/prometheus/common/expfmt/decode.go
index c092723..7657f84 100644
--- a/vendor/github.com/prometheus/common/expfmt/decode.go
+++ b/vendor/github.com/prometheus/common/expfmt/decode.go
@@ -164,7 +164,7 @@
}
// ExtractSamples builds a slice of samples from the provided metric
-// families. If an error occurrs during sample extraction, it continues to
+// families. If an error occurs during sample extraction, it continues to
// extract from the remaining metric families. The returned error is the last
// error that has occurred.
func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) (model.Vector, error) {
diff --git a/vendor/github.com/prometheus/common/expfmt/encode.go b/vendor/github.com/prometheus/common/expfmt/encode.go
index 11839ed..bd4e347 100644
--- a/vendor/github.com/prometheus/common/expfmt/encode.go
+++ b/vendor/github.com/prometheus/common/expfmt/encode.go
@@ -30,17 +30,38 @@
Encode(*dto.MetricFamily) error
}
-type encoder func(*dto.MetricFamily) error
-
-func (e encoder) Encode(v *dto.MetricFamily) error {
- return e(v)
+// Closer is implemented by Encoders that need to be closed to finalize
+// encoding. (For example, OpenMetrics needs a final `# EOF` line.)
+//
+// Note that all Encoder implementations returned from this package implement
+// Closer, too, even if the Close call is a no-op. This happens in preparation
+// for adding a Close method to the Encoder interface directly in a (mildly
+// breaking) release in the future.
+type Closer interface {
+ Close() error
}
-// Negotiate returns the Content-Type based on the given Accept header.
-// If no appropriate accepted type is found, FmtText is returned.
+type encoderCloser struct {
+ encode func(*dto.MetricFamily) error
+ close func() error
+}
+
+func (ec encoderCloser) Encode(v *dto.MetricFamily) error {
+ return ec.encode(v)
+}
+
+func (ec encoderCloser) Close() error {
+ return ec.close()
+}
+
+// Negotiate returns the Content-Type based on the given Accept header. If no
+// appropriate accepted type is found, FmtText is returned (which is the
+// Prometheus text format). This function will never negotiate FmtOpenMetrics,
+// as the support is still experimental. To include the option to negotiate
+// FmtOpenMetrics, use NegotiateOpenMetrics.
func Negotiate(h http.Header) Format {
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
- // Check for protocol buffer
+ ver := ac.Params["version"]
if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
switch ac.Params["encoding"] {
case "delimited":
@@ -51,8 +72,6 @@
return FmtProtoCompact
}
}
- // Check for text format.
- ver := ac.Params["version"]
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
return FmtText
}
@@ -60,29 +79,84 @@
return FmtText
}
-// NewEncoder returns a new encoder based on content type negotiation.
+// NegotiateIncludingOpenMetrics works like Negotiate but includes
+// FmtOpenMetrics as an option for the result. Note that this function is
+// temporary and will disappear once FmtOpenMetrics is fully supported and as
+// such may be negotiated by the normal Negotiate function.
+func NegotiateIncludingOpenMetrics(h http.Header) Format {
+ for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
+ ver := ac.Params["version"]
+ if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
+ switch ac.Params["encoding"] {
+ case "delimited":
+ return FmtProtoDelim
+ case "text":
+ return FmtProtoText
+ case "compact-text":
+ return FmtProtoCompact
+ }
+ }
+ if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
+ return FmtText
+ }
+ if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion || ver == "") {
+ return FmtOpenMetrics
+ }
+ }
+ return FmtText
+}
+
+// NewEncoder returns a new encoder based on content type negotiation. All
+// Encoder implementations returned by NewEncoder also implement Closer, and
+// callers should always call the Close method. It is currently only required
+// for FmtOpenMetrics, but a future (breaking) release will add the Close method
+// to the Encoder interface directly. The current version of the Encoder
+// interface is kept for backwards compatibility.
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
- })
+ return encoderCloser{
+ encode: func(v *dto.MetricFamily) error {
+ _, err := pbutil.WriteDelimited(w, v)
+ return err
+ },
+ close: func() error { return nil },
+ }
case FmtProtoCompact:
- return encoder(func(v *dto.MetricFamily) error {
- _, err := fmt.Fprintln(w, v.String())
- return err
- })
+ return encoderCloser{
+ encode: func(v *dto.MetricFamily) error {
+ _, err := fmt.Fprintln(w, v.String())
+ return err
+ },
+ close: func() error { return nil },
+ }
case FmtProtoText:
- return encoder(func(v *dto.MetricFamily) error {
- _, err := fmt.Fprintln(w, proto.MarshalTextString(v))
- return err
- })
+ return encoderCloser{
+ encode: func(v *dto.MetricFamily) error {
+ _, err := fmt.Fprintln(w, proto.MarshalTextString(v))
+ return err
+ },
+ close: func() error { return nil },
+ }
case FmtText:
- return encoder(func(v *dto.MetricFamily) error {
- _, err := MetricFamilyToText(w, v)
- return err
- })
+ return encoderCloser{
+ encode: func(v *dto.MetricFamily) error {
+ _, err := MetricFamilyToText(w, v)
+ return err
+ },
+ close: func() error { return nil },
+ }
+ case FmtOpenMetrics:
+ return encoderCloser{
+ encode: func(v *dto.MetricFamily) error {
+ _, err := MetricFamilyToOpenMetrics(w, v)
+ return err
+ },
+ close: func() error {
+ _, err := FinalizeOpenMetrics(w)
+ return err
+ },
+ }
}
- panic("expfmt.NewEncoder: unknown format")
+ panic(fmt.Errorf("expfmt.NewEncoder: unknown format %q", format))
}
diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go
index c71bcb9..0f176fa 100644
--- a/vendor/github.com/prometheus/common/expfmt/expfmt.go
+++ b/vendor/github.com/prometheus/common/expfmt/expfmt.go
@@ -19,10 +19,12 @@
// Constants to assemble the Content-Type values for the different wire protocols.
const (
- TextVersion = "0.0.4"
- ProtoType = `application/vnd.google.protobuf`
- ProtoProtocol = `io.prometheus.client.MetricFamily`
- ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
+ TextVersion = "0.0.4"
+ ProtoType = `application/vnd.google.protobuf`
+ ProtoProtocol = `io.prometheus.client.MetricFamily`
+ ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
+ OpenMetricsType = `application/openmetrics-text`
+ OpenMetricsVersion = "0.0.1"
// The Content-Type values for the different wire protocols.
FmtUnknown Format = `<unknown>`
@@ -30,6 +32,7 @@
FmtProtoDelim Format = ProtoFmt + ` encoding=delimited`
FmtProtoText Format = ProtoFmt + ` encoding=text`
FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
+ FmtOpenMetrics Format = OpenMetricsType + `; version=` + OpenMetricsVersion + `; charset=utf-8`
)
const (
diff --git a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
new file mode 100644
index 0000000..8a9313a
--- /dev/null
+++ b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
@@ -0,0 +1,527 @@
+// Copyright 2020 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 (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/golang/protobuf/ptypes"
+ "github.com/prometheus/common/model"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// MetricFamilyToOpenMetrics converts a MetricFamily proto message into the
+// OpenMetrics text format and writes the resulting lines to 'out'. It returns
+// the number of bytes written and any error encountered. The output will have
+// the same order as the input, no further sorting is performed. Furthermore,
+// this function assumes the input is already sanitized and does not perform any
+// sanity checks. If the input contains duplicate metrics or invalid metric or
+// label names, the conversion will result in invalid text format output.
+//
+// This function fulfills the type 'expfmt.encoder'.
+//
+// Note that OpenMetrics requires a final `# EOF` line. Since this function acts
+// on individual metric families, it is the responsibility of the caller to
+// append this line to 'out' once all metric families have been written.
+// Conveniently, this can be done by calling FinalizeOpenMetrics.
+//
+// The output should be fully OpenMetrics compliant. However, there are a few
+// missing features and peculiarities to avoid complications when switching from
+// Prometheus to OpenMetrics or vice versa:
+//
+// - Counters are expected to have the `_total` suffix in their metric name. In
+// the output, the suffix will be truncated from the `# TYPE` and `# HELP`
+// line. A counter with a missing `_total` suffix is not an error. However,
+// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
+// output.
+//
+// - No support for the following (optional) features: `# UNIT` line, `_created`
+// line, info type, stateset type, gaugehistogram type.
+//
+// - The size of exemplar labels is not checked (i.e. it's possible to create
+// exemplars that are larger than allowed by the OpenMetrics specification).
+//
+// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
+// with a `NaN` value.)
+func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int, err error) {
+ name := in.GetName()
+ if name == "" {
+ return 0, fmt.Errorf("MetricFamily has no name: %s", in)
+ }
+
+ // Try the interface upgrade. If it doesn't work, we'll use a
+ // bufio.Writer from the sync.Pool.
+ w, ok := out.(enhancedWriter)
+ if !ok {
+ b := bufPool.Get().(*bufio.Writer)
+ b.Reset(out)
+ w = b
+ defer func() {
+ bErr := b.Flush()
+ if err == nil {
+ err = bErr
+ }
+ bufPool.Put(b)
+ }()
+ }
+
+ var (
+ n int
+ metricType = in.GetType()
+ shortName = name
+ )
+ if metricType == dto.MetricType_COUNTER && strings.HasSuffix(shortName, "_total") {
+ shortName = name[:len(name)-6]
+ }
+
+ // Comments, first HELP, then TYPE.
+ if in.Help != nil {
+ n, err = w.WriteString("# HELP ")
+ written += n
+ if err != nil {
+ return
+ }
+ n, err = w.WriteString(shortName)
+ written += n
+ if err != nil {
+ return
+ }
+ err = w.WriteByte(' ')
+ written++
+ if err != nil {
+ return
+ }
+ n, err = writeEscapedString(w, *in.Help, true)
+ written += n
+ if err != nil {
+ return
+ }
+ err = w.WriteByte('\n')
+ written++
+ if err != nil {
+ return
+ }
+ }
+ n, err = w.WriteString("# TYPE ")
+ written += n
+ if err != nil {
+ return
+ }
+ n, err = w.WriteString(shortName)
+ written += n
+ if err != nil {
+ return
+ }
+ switch metricType {
+ case dto.MetricType_COUNTER:
+ if strings.HasSuffix(name, "_total") {
+ n, err = w.WriteString(" counter\n")
+ } else {
+ n, err = w.WriteString(" unknown\n")
+ }
+ case dto.MetricType_GAUGE:
+ n, err = w.WriteString(" gauge\n")
+ case dto.MetricType_SUMMARY:
+ n, err = w.WriteString(" summary\n")
+ case dto.MetricType_UNTYPED:
+ n, err = w.WriteString(" unknown\n")
+ case dto.MetricType_HISTOGRAM:
+ n, err = w.WriteString(" histogram\n")
+ default:
+ return written, fmt.Errorf("unknown metric type %s", metricType.String())
+ }
+ written += n
+ if err != nil {
+ return
+ }
+
+ // Finally the samples, one line for each.
+ for _, metric := range in.Metric {
+ switch metricType {
+ case dto.MetricType_COUNTER:
+ if metric.Counter == nil {
+ return written, fmt.Errorf(
+ "expected counter in metric %s %s", name, metric,
+ )
+ }
+ // Note that we have ensured above that either the name
+ // ends on `_total` or that the rendered type is
+ // `unknown`. Therefore, no `_total` must be added here.
+ n, err = writeOpenMetricsSample(
+ w, name, "", metric, "", 0,
+ metric.Counter.GetValue(), 0, false,
+ metric.Counter.Exemplar,
+ )
+ case dto.MetricType_GAUGE:
+ if metric.Gauge == nil {
+ return written, fmt.Errorf(
+ "expected gauge in metric %s %s", name, metric,
+ )
+ }
+ n, err = writeOpenMetricsSample(
+ w, name, "", metric, "", 0,
+ metric.Gauge.GetValue(), 0, false,
+ nil,
+ )
+ case dto.MetricType_UNTYPED:
+ if metric.Untyped == nil {
+ return written, fmt.Errorf(
+ "expected untyped in metric %s %s", name, metric,
+ )
+ }
+ n, err = writeOpenMetricsSample(
+ w, name, "", metric, "", 0,
+ metric.Untyped.GetValue(), 0, false,
+ nil,
+ )
+ case dto.MetricType_SUMMARY:
+ if metric.Summary == nil {
+ return written, fmt.Errorf(
+ "expected summary in metric %s %s", name, metric,
+ )
+ }
+ for _, q := range metric.Summary.Quantile {
+ n, err = writeOpenMetricsSample(
+ w, name, "", metric,
+ model.QuantileLabel, q.GetQuantile(),
+ q.GetValue(), 0, false,
+ nil,
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ }
+ n, err = writeOpenMetricsSample(
+ w, name, "_sum", metric, "", 0,
+ metric.Summary.GetSampleSum(), 0, false,
+ nil,
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ n, err = writeOpenMetricsSample(
+ w, name, "_count", metric, "", 0,
+ 0, metric.Summary.GetSampleCount(), true,
+ nil,
+ )
+ case dto.MetricType_HISTOGRAM:
+ if metric.Histogram == nil {
+ return written, fmt.Errorf(
+ "expected histogram in metric %s %s", name, metric,
+ )
+ }
+ infSeen := false
+ for _, b := range metric.Histogram.Bucket {
+ n, err = writeOpenMetricsSample(
+ w, name, "_bucket", metric,
+ model.BucketLabel, b.GetUpperBound(),
+ 0, b.GetCumulativeCount(), true,
+ b.Exemplar,
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ if math.IsInf(b.GetUpperBound(), +1) {
+ infSeen = true
+ }
+ }
+ if !infSeen {
+ n, err = writeOpenMetricsSample(
+ w, name, "_bucket", metric,
+ model.BucketLabel, math.Inf(+1),
+ 0, metric.Histogram.GetSampleCount(), true,
+ nil,
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ }
+ n, err = writeOpenMetricsSample(
+ w, name, "_sum", metric, "", 0,
+ metric.Histogram.GetSampleSum(), 0, false,
+ nil,
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ n, err = writeOpenMetricsSample(
+ w, name, "_count", metric, "", 0,
+ 0, metric.Histogram.GetSampleCount(), true,
+ nil,
+ )
+ default:
+ return written, fmt.Errorf(
+ "unexpected type in metric %s %s", name, metric,
+ )
+ }
+ written += n
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// FinalizeOpenMetrics writes the final `# EOF\n` line required by OpenMetrics.
+func FinalizeOpenMetrics(w io.Writer) (written int, err error) {
+ return w.Write([]byte("# EOF\n"))
+}
+
+// writeOpenMetricsSample writes a single sample in OpenMetrics text format to
+// w, given the metric name, the metric proto message itself, optionally an
+// additional label name with a float64 value (use empty string as label name if
+// not required), the value (optionally as float64 or uint64, determined by
+// useIntValue), and optionally an exemplar (use nil if not required). The
+// function returns the number of bytes written and any error encountered.
+func writeOpenMetricsSample(
+ w enhancedWriter,
+ name, suffix string,
+ metric *dto.Metric,
+ additionalLabelName string, additionalLabelValue float64,
+ floatValue float64, intValue uint64, useIntValue bool,
+ exemplar *dto.Exemplar,
+) (int, error) {
+ var written int
+ n, err := w.WriteString(name)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ if suffix != "" {
+ n, err = w.WriteString(suffix)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ }
+ n, err = writeOpenMetricsLabelPairs(
+ w, metric.Label, additionalLabelName, additionalLabelValue,
+ )
+ written += n
+ if err != nil {
+ return written, err
+ }
+ err = w.WriteByte(' ')
+ written++
+ if err != nil {
+ return written, err
+ }
+ if useIntValue {
+ n, err = writeUint(w, intValue)
+ } else {
+ n, err = writeOpenMetricsFloat(w, floatValue)
+ }
+ written += n
+ if err != nil {
+ return written, err
+ }
+ if metric.TimestampMs != nil {
+ err = w.WriteByte(' ')
+ written++
+ if err != nil {
+ return written, err
+ }
+ // TODO(beorn7): Format this directly without converting to a float first.
+ n, err = writeOpenMetricsFloat(w, float64(*metric.TimestampMs)/1000)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ }
+ if exemplar != nil {
+ n, err = writeExemplar(w, exemplar)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ }
+ err = w.WriteByte('\n')
+ written++
+ if err != nil {
+ return written, err
+ }
+ return written, nil
+}
+
+// writeOpenMetricsLabelPairs works like writeOpenMetrics but formats the float
+// in OpenMetrics style.
+func writeOpenMetricsLabelPairs(
+ w enhancedWriter,
+ in []*dto.LabelPair,
+ additionalLabelName string, additionalLabelValue float64,
+) (int, error) {
+ if len(in) == 0 && additionalLabelName == "" {
+ return 0, nil
+ }
+ var (
+ written int
+ separator byte = '{'
+ )
+ for _, lp := range in {
+ err := w.WriteByte(separator)
+ written++
+ if err != nil {
+ return written, err
+ }
+ n, err := w.WriteString(lp.GetName())
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = w.WriteString(`="`)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = writeEscapedString(w, lp.GetValue(), true)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ err = w.WriteByte('"')
+ written++
+ if err != nil {
+ return written, err
+ }
+ separator = ','
+ }
+ if additionalLabelName != "" {
+ err := w.WriteByte(separator)
+ written++
+ if err != nil {
+ return written, err
+ }
+ n, err := w.WriteString(additionalLabelName)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = w.WriteString(`="`)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = writeOpenMetricsFloat(w, additionalLabelValue)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ err = w.WriteByte('"')
+ written++
+ if err != nil {
+ return written, err
+ }
+ }
+ err := w.WriteByte('}')
+ written++
+ if err != nil {
+ return written, err
+ }
+ return written, nil
+}
+
+// writeExemplar writes the provided exemplar in OpenMetrics format to w. The
+// function returns the number of bytes written and any error encountered.
+func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) {
+ written := 0
+ n, err := w.WriteString(" # ")
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = writeOpenMetricsLabelPairs(w, e.Label, "", 0)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ err = w.WriteByte(' ')
+ written++
+ if err != nil {
+ return written, err
+ }
+ n, err = writeOpenMetricsFloat(w, e.GetValue())
+ written += n
+ if err != nil {
+ return written, err
+ }
+ if e.Timestamp != nil {
+ err = w.WriteByte(' ')
+ written++
+ if err != nil {
+ return written, err
+ }
+ ts, err := ptypes.Timestamp((*e).Timestamp)
+ if err != nil {
+ return written, err
+ }
+ // TODO(beorn7): Format this directly from components of ts to
+ // avoid overflow/underflow and precision issues of the float
+ // conversion.
+ n, err = writeOpenMetricsFloat(w, float64(ts.UnixNano())/1e9)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ }
+ return written, nil
+}
+
+// writeOpenMetricsFloat works like writeFloat but appends ".0" if the resulting
+// number would otherwise contain neither a "." nor an "e".
+func writeOpenMetricsFloat(w enhancedWriter, f float64) (int, error) {
+ switch {
+ case f == 1:
+ return w.WriteString("1.0")
+ case f == 0:
+ return w.WriteString("0.0")
+ case f == -1:
+ return w.WriteString("-1.0")
+ case math.IsNaN(f):
+ return w.WriteString("NaN")
+ case math.IsInf(f, +1):
+ return w.WriteString("+Inf")
+ case math.IsInf(f, -1):
+ return w.WriteString("-Inf")
+ default:
+ bp := numBufPool.Get().(*[]byte)
+ *bp = strconv.AppendFloat((*bp)[:0], f, 'g', -1, 64)
+ if !bytes.ContainsAny(*bp, "e.") {
+ *bp = append(*bp, '.', '0')
+ }
+ written, err := w.Write(*bp)
+ numBufPool.Put(bp)
+ return written, err
+ }
+}
+
+// writeUint is like writeInt just for uint64.
+func writeUint(w enhancedWriter, u uint64) (int, error) {
+ bp := numBufPool.Get().(*[]byte)
+ *bp = strconv.AppendUint((*bp)[:0], u, 10)
+ written, err := w.Write(*bp)
+ numBufPool.Put(bp)
+ return written, err
+}
diff --git a/vendor/github.com/prometheus/common/expfmt/text_create.go b/vendor/github.com/prometheus/common/expfmt/text_create.go
index 8e473d0..5ba503b 100644
--- a/vendor/github.com/prometheus/common/expfmt/text_create.go
+++ b/vendor/github.com/prometheus/common/expfmt/text_create.go
@@ -14,9 +14,10 @@
package expfmt
import (
- "bytes"
+ "bufio"
"fmt"
"io"
+ "io/ioutil"
"math"
"strconv"
"strings"
@@ -27,7 +28,7 @@
dto "github.com/prometheus/client_model/go"
)
-// enhancedWriter has all the enhanced write functions needed here. bytes.Buffer
+// enhancedWriter has all the enhanced write functions needed here. bufio.Writer
// implements it.
type enhancedWriter interface {
io.Writer
@@ -37,14 +38,13 @@
}
const (
- initialBufSize = 512
initialNumBufSize = 24
)
var (
bufPool = sync.Pool{
New: func() interface{} {
- return bytes.NewBuffer(make([]byte, 0, initialBufSize))
+ return bufio.NewWriter(ioutil.Discard)
},
}
numBufPool = sync.Pool{
@@ -75,16 +75,14 @@
}
// Try the interface upgrade. If it doesn't work, we'll use a
- // bytes.Buffer from the sync.Pool and write out its content to out in a
- // single go in the end.
+ // bufio.Writer from the sync.Pool.
w, ok := out.(enhancedWriter)
if !ok {
- b := bufPool.Get().(*bytes.Buffer)
- b.Reset()
+ b := bufPool.Get().(*bufio.Writer)
+ b.Reset(out)
w = b
defer func() {
- bWritten, bErr := out.Write(b.Bytes())
- written = bWritten
+ bErr := b.Flush()
if err == nil {
err = bErr
}
@@ -425,9 +423,8 @@
func writeEscapedString(w enhancedWriter, v string, includeDoubleQuote bool) (int, error) {
if includeDoubleQuote {
return quotedEscaper.WriteString(w, v)
- } else {
- return escaper.WriteString(w, v)
}
+ return escaper.WriteString(w, v)
}
// writeFloat is equivalent to fmt.Fprint with a float64 argument but hardcodes
diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go
index ec3d86b..b6079b3 100644
--- a/vendor/github.com/prometheus/common/expfmt/text_parse.go
+++ b/vendor/github.com/prometheus/common/expfmt/text_parse.go
@@ -299,6 +299,17 @@
p.parseError(fmt.Sprintf("expected '=' after label name, found %q", p.currentByte))
return nil
}
+ // Check for duplicate label names.
+ labels := make(map[string]struct{})
+ for _, l := range p.currentMetric.Label {
+ lName := l.GetName()
+ if _, exists := labels[lName]; !exists {
+ labels[lName] = struct{}{}
+ } else {
+ p.parseError(fmt.Sprintf("duplicate label names for metric %q", p.currentMF.GetName()))
+ return nil
+ }
+ }
return p.startLabelValue
}
@@ -325,7 +336,7 @@
// - Other labels have to be added to currentLabels for signature calculation.
if p.currentMF.GetType() == dto.MetricType_SUMMARY {
if p.currentLabelPair.GetName() == model.QuantileLabel {
- if p.currentQuantile, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil {
+ if p.currentQuantile, p.err = parseFloat(p.currentLabelPair.GetValue()); p.err != nil {
// Create a more helpful error message.
p.parseError(fmt.Sprintf("expected float as value for 'quantile' label, got %q", p.currentLabelPair.GetValue()))
return nil
@@ -337,7 +348,7 @@
// Similar special treatment of histograms.
if p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
if p.currentLabelPair.GetName() == model.BucketLabel {
- if p.currentBucket, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil {
+ if p.currentBucket, p.err = parseFloat(p.currentLabelPair.GetValue()); p.err != nil {
// Create a more helpful error message.
p.parseError(fmt.Sprintf("expected float as value for 'le' label, got %q", p.currentLabelPair.GetValue()))
return nil
@@ -392,7 +403,7 @@
if p.readTokenUntilWhitespace(); p.err != nil {
return nil // Unexpected end of input.
}
- value, err := strconv.ParseFloat(p.currentToken.String(), 64)
+ value, err := parseFloat(p.currentToken.String())
if err != nil {
// Create a more helpful error message.
p.parseError(fmt.Sprintf("expected float as value, got %q", p.currentToken.String()))
@@ -755,3 +766,10 @@
return name
}
}
+
+func parseFloat(s string) (float64, error) {
+ if strings.ContainsAny(s, "pP_") {
+ return 0, fmt.Errorf("unsupported character in float")
+ }
+ return strconv.ParseFloat(s, 64)
+}
diff --git a/vendor/github.com/prometheus/common/model/fnv.go b/vendor/github.com/prometheus/common/model/fnv.go
index 038fc1c..367afec 100644
--- a/vendor/github.com/prometheus/common/model/fnv.go
+++ b/vendor/github.com/prometheus/common/model/fnv.go
@@ -20,7 +20,7 @@
prime64 = 1099511628211
)
-// hashNew initializies a new fnv64a hash value.
+// hashNew initializes a new fnv64a hash value.
func hashNew() uint64 {
return offset64
}
diff --git a/vendor/github.com/prometheus/common/model/labels.go b/vendor/github.com/prometheus/common/model/labels.go
index 41051a0..ef89563 100644
--- a/vendor/github.com/prometheus/common/model/labels.go
+++ b/vendor/github.com/prometheus/common/model/labels.go
@@ -45,6 +45,14 @@
// scrape a target.
MetricsPathLabel = "__metrics_path__"
+ // ScrapeIntervalLabel is the name of the label that holds the scrape interval
+ // used to scrape a target.
+ ScrapeIntervalLabel = "__scrape_interval__"
+
+ // ScrapeTimeoutLabel is the name of the label that holds the scrape
+ // timeout used to scrape a target.
+ ScrapeTimeoutLabel = "__scrape_timeout__"
+
// ReservedLabelPrefix is a prefix which is not legal in user-supplied
// label names.
ReservedLabelPrefix = "__"
diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go
index 7b0064f..7f67b16 100644
--- a/vendor/github.com/prometheus/common/model/time.go
+++ b/vendor/github.com/prometheus/common/model/time.go
@@ -14,6 +14,8 @@
package model
import (
+ "encoding/json"
+ "errors"
"fmt"
"math"
"regexp"
@@ -181,73 +183,118 @@
return "duration"
}
-var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$")
+var durationRE = regexp.MustCompile("^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$")
// ParseDuration parses a string into a time.Duration, assuming that a year
// always has 365d, a week always has 7d, and a day always has 24h.
func ParseDuration(durationStr string) (Duration, error) {
+ switch durationStr {
+ case "0":
+ // Allow 0 without a unit.
+ return 0, nil
+ case "":
+ return 0, fmt.Errorf("empty duration string")
+ }
matches := durationRE.FindStringSubmatch(durationStr)
- if len(matches) != 3 {
+ if matches == nil {
return 0, fmt.Errorf("not a valid duration string: %q", durationStr)
}
- var (
- n, _ = strconv.Atoi(matches[1])
- dur = time.Duration(n) * time.Millisecond
- )
- switch unit := matches[2]; unit {
- case "y":
- dur *= 1000 * 60 * 60 * 24 * 365
- case "w":
- dur *= 1000 * 60 * 60 * 24 * 7
- case "d":
- dur *= 1000 * 60 * 60 * 24
- case "h":
- dur *= 1000 * 60 * 60
- case "m":
- dur *= 1000 * 60
- case "s":
- dur *= 1000
- case "ms":
- // Value already correct
- default:
- return 0, fmt.Errorf("invalid time unit in duration string: %q", unit)
+ var dur time.Duration
+
+ // Parse the match at pos `pos` in the regex and use `mult` to turn that
+ // into ms, then add that value to the total parsed duration.
+ var overflowErr error
+ m := func(pos int, mult time.Duration) {
+ if matches[pos] == "" {
+ return
+ }
+ n, _ := strconv.Atoi(matches[pos])
+
+ // Check if the provided duration overflows time.Duration (> ~ 290years).
+ if n > int((1<<63-1)/mult/time.Millisecond) {
+ overflowErr = errors.New("duration out of range")
+ }
+ d := time.Duration(n) * time.Millisecond
+ dur += d * mult
+
+ if dur < 0 {
+ overflowErr = errors.New("duration out of range")
+ }
}
- return Duration(dur), nil
+
+ m(2, 1000*60*60*24*365) // y
+ m(4, 1000*60*60*24*7) // w
+ m(6, 1000*60*60*24) // d
+ m(8, 1000*60*60) // h
+ m(10, 1000*60) // m
+ m(12, 1000) // s
+ m(14, 1) // ms
+
+ return Duration(dur), overflowErr
}
func (d Duration) String() string {
var (
- ms = int64(time.Duration(d) / time.Millisecond)
- unit = "ms"
+ ms = int64(time.Duration(d) / time.Millisecond)
+ r = ""
)
if ms == 0 {
return "0s"
}
- factors := map[string]int64{
- "y": 1000 * 60 * 60 * 24 * 365,
- "w": 1000 * 60 * 60 * 24 * 7,
- "d": 1000 * 60 * 60 * 24,
- "h": 1000 * 60 * 60,
- "m": 1000 * 60,
- "s": 1000,
- "ms": 1,
+
+ f := func(unit string, mult int64, exact bool) {
+ if exact && ms%mult != 0 {
+ return
+ }
+ if v := ms / mult; v > 0 {
+ r += fmt.Sprintf("%d%s", v, unit)
+ ms -= v * mult
+ }
}
- switch int64(0) {
- case ms % factors["y"]:
- unit = "y"
- case ms % factors["w"]:
- unit = "w"
- case ms % factors["d"]:
- unit = "d"
- case ms % factors["h"]:
- unit = "h"
- case ms % factors["m"]:
- unit = "m"
- case ms % factors["s"]:
- unit = "s"
+ // Only format years and weeks if the remainder is zero, as it is often
+ // easier to read 90d than 12w6d.
+ f("y", 1000*60*60*24*365, true)
+ f("w", 1000*60*60*24*7, true)
+
+ f("d", 1000*60*60*24, false)
+ f("h", 1000*60*60, false)
+ f("m", 1000*60, false)
+ f("s", 1000, false)
+ f("ms", 1, false)
+
+ return r
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (d Duration) MarshalJSON() ([]byte, error) {
+ return json.Marshal(d.String())
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (d *Duration) UnmarshalJSON(bytes []byte) error {
+ var s string
+ if err := json.Unmarshal(bytes, &s); err != nil {
+ return err
}
- return fmt.Sprintf("%v%v", ms/factors[unit], unit)
+ dur, err := ParseDuration(s)
+ if err != nil {
+ return err
+ }
+ *d = dur
+ return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (d *Duration) MarshalText() ([]byte, error) {
+ return []byte(d.String()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (d *Duration) UnmarshalText(text []byte) error {
+ var err error
+ *d, err = ParseDuration(string(text))
+ return err
}
// MarshalYAML implements the yaml.Marshaler interface.