vendor: update docker/go-metrics v0.0.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2020-01-08 18:27:59 +01:00
parent 6b972e50fe
commit 98dcc5195e
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
216 changed files with 25458 additions and 3611 deletions

View file

@ -14,13 +14,45 @@
package expfmt
import (
"bytes"
"fmt"
"io"
"math"
"strconv"
"strings"
"sync"
"github.com/prometheus/common/model"
dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/model"
)
// enhancedWriter has all the enhanced write functions needed here. bytes.Buffer
// implements it.
type enhancedWriter interface {
io.Writer
WriteRune(r rune) (n int, err error)
WriteString(s string) (n int, err error)
WriteByte(c byte) error
}
const (
initialBufSize = 512
initialNumBufSize = 24
)
var (
bufPool = sync.Pool{
New: func() interface{} {
return bytes.NewBuffer(make([]byte, 0, initialBufSize))
},
}
numBufPool = sync.Pool{
New: func() interface{} {
b := make([]byte, 0, initialNumBufSize)
return &b
},
}
)
// MetricFamilyToText converts a MetricFamily proto message into text format and
@ -32,37 +64,92 @@ import (
// will result in invalid text format output.
//
// This method fulfills the type 'prometheus.encoder'.
func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
var written int
func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) {
// Fail-fast checks.
if len(in.Metric) == 0 {
return written, fmt.Errorf("MetricFamily has no metrics: %s", in)
return 0, fmt.Errorf("MetricFamily has no metrics: %s", in)
}
name := in.GetName()
if name == "" {
return written, fmt.Errorf("MetricFamily has no name: %s", in)
return 0, fmt.Errorf("MetricFamily has no name: %s", in)
}
// 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.
w, ok := out.(enhancedWriter)
if !ok {
b := bufPool.Get().(*bytes.Buffer)
b.Reset()
w = b
defer func() {
bWritten, bErr := out.Write(b.Bytes())
written = bWritten
if err == nil {
err = bErr
}
bufPool.Put(b)
}()
}
var n int
// Comments, first HELP, then TYPE.
if in.Help != nil {
n, err := fmt.Fprintf(
out, "# HELP %s %s\n",
name, escapeString(*in.Help, false),
)
n, err = w.WriteString("# HELP ")
written += n
if err != nil {
return written, err
return
}
n, err = w.WriteString(name)
written += n
if err != nil {
return
}
err = w.WriteByte(' ')
written++
if err != nil {
return
}
n, err = writeEscapedString(w, *in.Help, false)
written += n
if err != nil {
return
}
err = w.WriteByte('\n')
written++
if err != nil {
return
}
}
metricType := in.GetType()
n, err := fmt.Fprintf(
out, "# TYPE %s %s\n",
name, strings.ToLower(metricType.String()),
)
n, err = w.WriteString("# TYPE ")
written += n
if err != nil {
return written, err
return
}
n, err = w.WriteString(name)
written += n
if err != nil {
return
}
metricType := in.GetType()
switch metricType {
case dto.MetricType_COUNTER:
n, err = w.WriteString(" counter\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(" untyped\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.
@ -75,9 +162,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
)
}
n, err = writeSample(
name, metric, "", "",
w, name, "", metric, "", 0,
metric.Counter.GetValue(),
out,
)
case dto.MetricType_GAUGE:
if metric.Gauge == nil {
@ -86,9 +172,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
)
}
n, err = writeSample(
name, metric, "", "",
w, name, "", metric, "", 0,
metric.Gauge.GetValue(),
out,
)
case dto.MetricType_UNTYPED:
if metric.Untyped == nil {
@ -97,9 +182,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
)
}
n, err = writeSample(
name, metric, "", "",
w, name, "", metric, "", 0,
metric.Untyped.GetValue(),
out,
)
case dto.MetricType_SUMMARY:
if metric.Summary == nil {
@ -109,29 +193,26 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
}
for _, q := range metric.Summary.Quantile {
n, err = writeSample(
name, metric,
model.QuantileLabel, fmt.Sprint(q.GetQuantile()),
w, name, "", metric,
model.QuantileLabel, q.GetQuantile(),
q.GetValue(),
out,
)
written += n
if err != nil {
return written, err
return
}
}
n, err = writeSample(
name+"_sum", metric, "", "",
w, name, "_sum", metric, "", 0,
metric.Summary.GetSampleSum(),
out,
)
if err != nil {
return written, err
}
written += n
if err != nil {
return
}
n, err = writeSample(
name+"_count", metric, "", "",
w, name, "_count", metric, "", 0,
float64(metric.Summary.GetSampleCount()),
out,
)
case dto.MetricType_HISTOGRAM:
if metric.Histogram == nil {
@ -140,46 +221,42 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
)
}
infSeen := false
for _, q := range metric.Histogram.Bucket {
for _, b := range metric.Histogram.Bucket {
n, err = writeSample(
name+"_bucket", metric,
model.BucketLabel, fmt.Sprint(q.GetUpperBound()),
float64(q.GetCumulativeCount()),
out,
w, name, "_bucket", metric,
model.BucketLabel, b.GetUpperBound(),
float64(b.GetCumulativeCount()),
)
written += n
if err != nil {
return written, err
return
}
if math.IsInf(q.GetUpperBound(), +1) {
if math.IsInf(b.GetUpperBound(), +1) {
infSeen = true
}
}
if !infSeen {
n, err = writeSample(
name+"_bucket", metric,
model.BucketLabel, "+Inf",
w, name, "_bucket", metric,
model.BucketLabel, math.Inf(+1),
float64(metric.Histogram.GetSampleCount()),
out,
)
if err != nil {
return written, err
}
written += n
if err != nil {
return
}
}
n, err = writeSample(
name+"_sum", metric, "", "",
w, name, "_sum", metric, "", 0,
metric.Histogram.GetSampleSum(),
out,
)
if err != nil {
return written, err
}
written += n
if err != nil {
return
}
n, err = writeSample(
name+"_count", metric, "", "",
w, name, "_count", metric, "", 0,
float64(metric.Histogram.GetSampleCount()),
out,
)
default:
return written, fmt.Errorf(
@ -188,116 +265,204 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
}
written += n
if err != nil {
return written, err
return
}
}
return written, nil
return
}
// writeSample writes a single sample in text format to out, given the metric
// writeSample writes a single sample in text format to w, given the metric
// name, the metric proto message itself, optionally an additional label name
// and value (use empty strings if not required), and the value. The function
// returns the number of bytes written and any error encountered.
// with a float64 value (use empty string as label name if not required), and
// the value. The function returns the number of bytes written and any error
// encountered.
func writeSample(
name string,
w enhancedWriter,
name, suffix string,
metric *dto.Metric,
additionalLabelName, additionalLabelValue string,
additionalLabelName string, additionalLabelValue float64,
value float64,
out io.Writer,
) (int, error) {
var written int
n, err := fmt.Fprint(out, name)
n, err := w.WriteString(name)
written += n
if err != nil {
return written, err
}
n, err = labelPairsToText(
metric.Label,
additionalLabelName, additionalLabelValue,
out,
)
written += n
if err != nil {
return written, err
}
n, err = fmt.Fprintf(out, " %v", value)
written += n
if err != nil {
return written, err
}
if metric.TimestampMs != nil {
n, err = fmt.Fprintf(out, " %v", *metric.TimestampMs)
if suffix != "" {
n, err = w.WriteString(suffix)
written += n
if err != nil {
return written, err
}
}
n, err = out.Write([]byte{'\n'})
n, err = writeLabelPairs(
w, metric.Label, additionalLabelName, additionalLabelValue,
)
written += n
if err != nil {
return written, err
}
err = w.WriteByte(' ')
written++
if err != nil {
return written, err
}
n, err = writeFloat(w, value)
written += n
if err != nil {
return written, err
}
if metric.TimestampMs != nil {
err = w.WriteByte(' ')
written++
if err != nil {
return written, err
}
n, err = writeInt(w, *metric.TimestampMs)
written += n
if err != nil {
return written, err
}
}
err = w.WriteByte('\n')
written++
if err != nil {
return written, err
}
return written, nil
}
// labelPairsToText converts a slice of LabelPair proto messages plus the
// writeLabelPairs converts a slice of LabelPair proto messages plus the
// explicitly given additional label pair into text formatted as required by the
// text format and writes it to 'out'. An empty slice in combination with an
// empty string 'additionalLabelName' results in nothing being
// written. Otherwise, the label pairs are written, escaped as required by the
// text format, and enclosed in '{...}'. The function returns the number of
// bytes written and any error encountered.
func labelPairsToText(
// text format and writes it to 'w'. An empty slice in combination with an empty
// string 'additionalLabelName' results in nothing being written. Otherwise, the
// label pairs are written, escaped as required by the text format, and enclosed
// in '{...}'. The function returns the number of bytes written and any error
// encountered.
func writeLabelPairs(
w enhancedWriter,
in []*dto.LabelPair,
additionalLabelName, additionalLabelValue string,
out io.Writer,
additionalLabelName string, additionalLabelValue float64,
) (int, error) {
if len(in) == 0 && additionalLabelName == "" {
return 0, nil
}
var written int
separator := '{'
var (
written int
separator byte = '{'
)
for _, lp := range in {
n, err := fmt.Fprintf(
out, `%c%s="%s"`,
separator, lp.GetName(), escapeString(lp.GetValue(), true),
)
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 != "" {
n, err := fmt.Fprintf(
out, `%c%s="%s"`,
separator, additionalLabelName,
escapeString(additionalLabelValue, true),
)
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 = writeFloat(w, additionalLabelValue)
written += n
if err != nil {
return written, err
}
err = w.WriteByte('"')
written++
if err != nil {
return written, err
}
}
n, err := out.Write([]byte{'}'})
written += n
err := w.WriteByte('}')
written++
if err != nil {
return written, err
}
return written, nil
}
// writeEscapedString replaces '\' by '\\', new line character by '\n', and - if
// includeDoubleQuote is true - '"' by '\"'.
var (
escape = strings.NewReplacer("\\", `\\`, "\n", `\n`)
escapeWithDoubleQuote = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`)
escaper = strings.NewReplacer("\\", `\\`, "\n", `\n`)
quotedEscaper = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`)
)
// escapeString replaces '\' by '\\', new line character by '\n', and - if
// includeDoubleQuote is true - '"' by '\"'.
func escapeString(v string, includeDoubleQuote bool) string {
func writeEscapedString(w enhancedWriter, v string, includeDoubleQuote bool) (int, error) {
if includeDoubleQuote {
return escapeWithDoubleQuote.Replace(v)
return quotedEscaper.WriteString(w, v)
} else {
return escaper.WriteString(w, v)
}
return escape.Replace(v)
}
// writeFloat is equivalent to fmt.Fprint with a float64 argument but hardcodes
// a few common cases for increased efficiency. For non-hardcoded cases, it uses
// strconv.AppendFloat to avoid allocations, similar to writeInt.
func writeFloat(w enhancedWriter, f float64) (int, error) {
switch {
case f == 1:
return 1, w.WriteByte('1')
case f == 0:
return 1, w.WriteByte('0')
case f == -1:
return w.WriteString("-1")
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)
written, err := w.Write(*bp)
numBufPool.Put(bp)
return written, err
}
}
// writeInt is equivalent to fmt.Fprint with an int64 argument but uses
// strconv.AppendInt with a byte slice taken from a sync.Pool to avoid
// allocations.
func writeInt(w enhancedWriter, i int64) (int, error) {
bp := numBufPool.Get().(*[]byte)
*bp = strconv.AppendInt((*bp)[:0], i, 10)
written, err := w.Write(*bp)
numBufPool.Put(bp)
return written, err
}