From 5dcce32ef876e70ffd22fdfaa0ecc44e3c441f86 Mon Sep 17 00:00:00 2001 From: Alex Yu Date: Fri, 23 Nov 2018 08:22:40 -0500 Subject: [PATCH] update promlog to latest version (#4876) * update promlog to latest version Signed-off-by: Alex Yu * Update api tests, fix main setup Signed-off-by: Alex Yu * tidy go.sum Signed-off-by: Alex Yu * revendor prometheus/common Signed-off-by: Alex Yu * only initialize config; use kingpin for remote_storage_adapter Signed-off-by: Alex Yu * actually parse the flags Signed-off-by: Alex Yu * clean up imports Signed-off-by: Alex Yu --- cmd/prometheus/main.go | 7 +- .../remote_storage_adapter/main.go | 79 ++-- go.mod | 2 +- go.sum | 4 +- .../prometheus/common/expfmt/text_create.go | 385 +++++++++++++----- .../prometheus/common/expfmt/text_parse.go | 2 +- .../prometheus/common/model/time.go | 2 +- .../prometheus/common/promlog/flag/flag.go | 16 +- .../prometheus/common/promlog/log.go | 40 +- .../prometheus/common/route/route.go | 2 +- vendor/modules.txt | 2 +- web/api/v1/api_test.go | 9 +- 12 files changed, 385 insertions(+), 165 deletions(-) diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index db011d056..a7b593f11 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -101,11 +101,12 @@ func main() { prometheusURL string - logLevel promlog.AllowedLevel + promlogConfig promlog.Config }{ notifier: notifier.Options{ Registerer: prometheus.DefaultRegisterer, }, + promlogConfig: promlog.Config{}, } a := kingpin.New(filepath.Base(os.Args[0]), "The Prometheus monitoring server") @@ -204,7 +205,7 @@ func main() { a.Flag("query.max-samples", "Maximum number of samples a single query can load into memory. Note that queries will fail if they would load more samples than this into memory, so this also limits the number of samples a query can return."). Default("50000000").IntVar(&cfg.queryMaxSamples) - promlogflag.AddFlags(a, &cfg.logLevel) + promlogflag.AddFlags(a, &cfg.promlogConfig) _, err := a.Parse(os.Args[1:]) if err != nil { @@ -233,7 +234,7 @@ func main() { promql.LookbackDelta = time.Duration(cfg.lookbackDelta) - logger := promlog.New(cfg.logLevel) + logger := promlog.New(&cfg.promlogConfig) // XXX(fabxc): Kubernetes does background logging which we can only customize by modifying // a global variable. diff --git a/documentation/examples/remote_storage/remote_storage_adapter/main.go b/documentation/examples/remote_storage/remote_storage_adapter/main.go index e2f2bc488..0829f0596 100644 --- a/documentation/examples/remote_storage/remote_storage_adapter/main.go +++ b/documentation/examples/remote_storage/remote_storage_adapter/main.go @@ -15,13 +15,13 @@ package main import ( - "flag" "fmt" "io/ioutil" "net/http" _ "net/http/pprof" "net/url" "os" + "path/filepath" "sync" "time" @@ -29,13 +29,17 @@ import ( "github.com/go-kit/kit/log/level" "github.com/gogo/protobuf/proto" "github.com/golang/snappy" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/model" + "gopkg.in/alecthomas/kingpin.v2" influx "github.com/influxdata/influxdb/client/v2" "github.com/prometheus/common/promlog" + "github.com/prometheus/common/promlog/flag" + "github.com/prometheus/prometheus/documentation/examples/remote_storage/remote_storage_adapter/graphite" "github.com/prometheus/prometheus/documentation/examples/remote_storage/remote_storage_adapter/influxdb" "github.com/prometheus/prometheus/documentation/examples/remote_storage/remote_storage_adapter/opentsdb" @@ -55,7 +59,7 @@ type config struct { remoteTimeout time.Duration listenAddr string telemetryPath string - logLevel string + promlogConfig promlog.Config } var ( @@ -100,11 +104,7 @@ func main() { cfg := parseFlags() http.Handle(cfg.telemetryPath, promhttp.Handler()) - logLevel := promlog.AllowedLevel{} - if err := logLevel.Set(cfg.logLevel); err != nil { - panic(fmt.Sprintf("Error setting log level: %v", err)) - } - logger := promlog.New(logLevel) + logger := promlog.New(&cfg.promlogConfig) writers, readers := buildClients(logger, cfg) if err := serve(logger, cfg.listenAddr, writers, readers); err != nil { @@ -114,42 +114,45 @@ func main() { } func parseFlags() *config { + a := kingpin.New(filepath.Base(os.Args[0]), "Remote storage adapter") + a.HelpFlag.Short('h') + cfg := &config{ influxdbPassword: os.Getenv("INFLUXDB_PW"), + promlogConfig: promlog.Config{}, } - flag.StringVar(&cfg.graphiteAddress, "graphite-address", "", - "The host:port of the Graphite server to send samples to. None, if empty.", - ) - flag.StringVar(&cfg.graphiteTransport, "graphite-transport", "tcp", - "Transport protocol to use to communicate with Graphite. 'tcp', if empty.", - ) - flag.StringVar(&cfg.graphitePrefix, "graphite-prefix", "", - "The prefix to prepend to all metrics exported to Graphite. None, if empty.", - ) - flag.StringVar(&cfg.opentsdbURL, "opentsdb-url", "", - "The URL of the remote OpenTSDB server to send samples to. None, if empty.", - ) - flag.StringVar(&cfg.influxdbURL, "influxdb-url", "", - "The URL of the remote InfluxDB server to send samples to. None, if empty.", - ) - flag.StringVar(&cfg.influxdbRetentionPolicy, "influxdb.retention-policy", "autogen", - "The InfluxDB retention policy to use.", - ) - flag.StringVar(&cfg.influxdbUsername, "influxdb.username", "", - "The username to use when sending samples to InfluxDB. The corresponding password must be provided via the INFLUXDB_PW environment variable.", - ) - flag.StringVar(&cfg.influxdbDatabase, "influxdb.database", "prometheus", - "The name of the database to use for storing samples in InfluxDB.", - ) - flag.DurationVar(&cfg.remoteTimeout, "send-timeout", 30*time.Second, - "The timeout to use when sending samples to the remote storage.", - ) - flag.StringVar(&cfg.listenAddr, "web.listen-address", ":9201", "Address to listen on for web endpoints.") - flag.StringVar(&cfg.telemetryPath, "web.telemetry-path", "/metrics", "Address to listen on for web endpoints.") - flag.StringVar(&cfg.logLevel, "log.level", "debug", "Only log messages with the given severity or above. One of: [debug, info, warn, error]") + a.Flag("graphite-address", "The host:port of the Graphite server to send samples to. None, if empty."). + Default("").StringVar(&cfg.graphiteAddress) + a.Flag("graphite-transport", "Transport protocol to use to communicate with Graphite. 'tcp', if empty."). + Default("tcp").StringVar(&cfg.graphiteTransport) + a.Flag("graphite-prefix", "The prefix to prepend to all metrics exported to Graphite. None, if empty."). + Default("").StringVar(&cfg.graphitePrefix) + a.Flag("opentsdb-url", "The URL of the remote OpenTSDB server to send samples to. None, if empty."). + Default("").StringVar(&cfg.opentsdbURL) + a.Flag("influxdb-url", "The URL of the remote InfluxDB server to send samples to. None, if empty."). + Default("").StringVar(&cfg.influxdbURL) + a.Flag("influxdb.retention-policy", "The InfluxDB retention policy to use."). + Default("autogen").StringVar(&cfg.influxdbRetentionPolicy) + a.Flag("influxdb.username", "The username to use when sending samples to InfluxDB. The corresponding password must be provided via the INFLUXDB_PW environment variable."). + Default("").StringVar(&cfg.influxdbUsername) + a.Flag("influxdb.database", "The name of the database to use for storing samples in InfluxDB."). + Default("prometheus").StringVar(&cfg.influxdbDatabase) + a.Flag("send-timeout", "The timeout to use when sending samples to the remote storage."). + Default("30s").DurationVar(&cfg.remoteTimeout) + a.Flag("web.listen-address", "Address to listen on for web endpoints."). + Default(":9201").StringVar(&cfg.listenAddr) + a.Flag("web.telemetry-path", "Address to listen on for web endpoints."). + Default("/metrics").StringVar(&cfg.telemetryPath) - flag.Parse() + flag.AddFlags(a, &cfg.promlogConfig) + + _, err := a.Parse(os.Args[1:]) + if err != nil { + fmt.Fprintln(os.Stderr, errors.Wrapf(err, "Error parsing commandline arguments")) + a.Usage(os.Args[1:]) + os.Exit(2) + } return cfg } diff --git a/go.mod b/go.mod index 599796f50..31d043526 100644 --- a/go.mod +++ b/go.mod @@ -103,7 +103,7 @@ require ( github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0 // indirect github.com/prometheus/client_golang v0.0.0-20181001174001-0a8115f42e03 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 - github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 + github.com/prometheus/common v0.0.0-20181119215939-b36ad289a3ea github.com/prometheus/procfs v0.0.0-20160411190841-abf152e5f3e9 // indirect github.com/prometheus/tsdb v0.2.0 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect diff --git a/go.sum b/go.sum index 030a9a072..c5d82ef85 100644 --- a/go.sum +++ b/go.sum @@ -211,8 +211,8 @@ github.com/prometheus/client_golang v0.0.0-20181001174001-0a8115f42e03 h1:716+Mw github.com/prometheus/client_golang v0.0.0-20181001174001-0a8115f42e03/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 h1:osmNoEW2SCW3L7EX0km2LYM8HKpNWRiouxjE3XHkyGc= -github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181119215939-b36ad289a3ea h1:4RkbEb5XX0Wvu3XhIW3zxgLUhUE9suNc7YLO52/RyT4= +github.com/prometheus/common v0.0.0-20181119215939-b36ad289a3ea/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/procfs v0.0.0-20160411190841-abf152e5f3e9 h1:IrO4Eb9oGw+GxzOhO4b2QC5EWO85Omh/4iTSPZktMm8= github.com/prometheus/procfs v0.0.0-20160411190841-abf152e5f3e9/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/tsdb v0.2.0 h1:27z98vFd/gPew17nmKEbLn37exGCwc2F5EyrgScg6bk= diff --git a/vendor/github.com/prometheus/common/expfmt/text_create.go b/vendor/github.com/prometheus/common/expfmt/text_create.go index f11321cd0..8e473d0fe 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_create.go +++ b/vendor/github.com/prometheus/common/expfmt/text_create.go @@ -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 } diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go index b86290afa..ec3d86ba7 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_parse.go +++ b/vendor/github.com/prometheus/common/expfmt/text_parse.go @@ -359,7 +359,7 @@ func (p *TextParser) startLabelValue() stateFn { } return p.readingValue default: - p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.Value)) + p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.GetValue())) return nil } } diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go index 74ed5a9f7..46259b1f1 100644 --- a/vendor/github.com/prometheus/common/model/time.go +++ b/vendor/github.com/prometheus/common/model/time.go @@ -43,7 +43,7 @@ const ( // (1970-01-01 00:00 UTC) excluding leap seconds. type Time int64 -// Interval describes and interval between two timestamps. +// Interval describes an interval between two timestamps. type Interval struct { Start, End Time } diff --git a/vendor/github.com/prometheus/common/promlog/flag/flag.go b/vendor/github.com/prometheus/common/promlog/flag/flag.go index b9d361e43..ec55008b8 100644 --- a/vendor/github.com/prometheus/common/promlog/flag/flag.go +++ b/vendor/github.com/prometheus/common/promlog/flag/flag.go @@ -25,9 +25,21 @@ const LevelFlagName = "log.level" // LevelFlagHelp is the help description for the log.level flag. const LevelFlagHelp = "Only log messages with the given severity or above. One of: [debug, info, warn, error]" +// FormatFlagName is the canonical flag name to configure the log format +// within Prometheus projects. +const FormatFlagName = "log.format" + +// FormatFlagHelp is the help description for the log.format flag. +const FormatFlagHelp = "Output format of log messages. One of: [logfmt, json]" + // AddFlags adds the flags used by this package to the Kingpin application. // To use the default Kingpin application, call AddFlags(kingpin.CommandLine) -func AddFlags(a *kingpin.Application, logLevel *promlog.AllowedLevel) { +func AddFlags(a *kingpin.Application, config *promlog.Config) { + config.Level = &promlog.AllowedLevel{} a.Flag(LevelFlagName, LevelFlagHelp). - Default("info").SetValue(logLevel) + Default("info").SetValue(config.Level) + + config.Format = &promlog.AllowedFormat{} + a.Flag(FormatFlagName, FormatFlagHelp). + Default("logfmt").SetValue(config.Format) } diff --git a/vendor/github.com/prometheus/common/promlog/log.go b/vendor/github.com/prometheus/common/promlog/log.go index cf8307ad2..059b2aef0 100644 --- a/vendor/github.com/prometheus/common/promlog/log.go +++ b/vendor/github.com/prometheus/common/promlog/log.go @@ -53,11 +53,43 @@ func (l *AllowedLevel) Set(s string) error { return nil } -// New returns a new leveled oklog logger in the logfmt format. Each logged line will be annotated +// AllowedFormat is a settable identifier for the output format that the logger can have. +type AllowedFormat struct { + s string +} + +func (f *AllowedFormat) String() string { + return f.s +} + +// Set updates the value of the allowed format. +func (f *AllowedFormat) Set(s string) error { + switch s { + case "logfmt", "json": + f.s = s + default: + return errors.Errorf("unrecognized log format %q", s) + } + return nil +} + +// Config is a struct containing configurable settings for the logger +type Config struct { + Level *AllowedLevel + Format *AllowedFormat +} + +// New returns a new leveled oklog logger. Each logged line will be annotated // with a timestamp. The output always goes to stderr. -func New(al AllowedLevel) log.Logger { - l := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) - l = level.NewFilter(l, al.o) +func New(config *Config) log.Logger { + var l log.Logger + if config.Format.s == "logfmt" { + l = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) + } else { + l = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) + } + + l = level.NewFilter(l, config.Level.o) l = log.With(l, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) return l } diff --git a/vendor/github.com/prometheus/common/route/route.go b/vendor/github.com/prometheus/common/route/route.go index 742e57547..66c9d48f9 100644 --- a/vendor/github.com/prometheus/common/route/route.go +++ b/vendor/github.com/prometheus/common/route/route.go @@ -1,10 +1,10 @@ package route import ( + "context" "net/http" "github.com/julienschmidt/httprouter" - "golang.org/x/net/context" ) type param string diff --git a/vendor/modules.txt b/vendor/modules.txt index 7a0e7cdff..dafa6bf47 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -175,7 +175,7 @@ github.com/prometheus/client_golang/prometheus/promhttp github.com/prometheus/client_golang/prometheus/internal # github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 github.com/prometheus/client_model/go -# github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 +# github.com/prometheus/common v0.0.0-20181119215939-b36ad289a3ea github.com/prometheus/common/model github.com/prometheus/common/promlog github.com/prometheus/common/promlog/flag diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index 8ed0264a8..f0b35db9f 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -272,7 +272,14 @@ func TestEndpoints(t *testing.T) { al := promlog.AllowedLevel{} al.Set("debug") - remote := remote.NewStorage(promlog.New(al), func() (int64, error) { + af := promlog.AllowedFormat{} + al.Set("logfmt") + promlogConfig := promlog.Config{ + Level: &al, + Format: &af, + } + + remote := remote.NewStorage(promlog.New(&promlogConfig), func() (int64, error) { return 0, nil }, 1*time.Second)