瀏覽代碼

vendor: bump etcd deps

As per https://github.com/etcd-io/etcd/blob/fa57f7fbc787b4/Gopkg.lock

List of packages required by subset of etcd used is provided by:

go list -f '{{join .Deps "\n"}}' \
 github.com/docker/docker/vendor/github.com/coreos/etcd/... \
 | grep -F . | grep -v coreos/etcd | sort | uniq

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 7008ac01fa4dbde9a069cc647a09c982f3648fc3)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Kir Kolyshkin 6 年之前
父節點
當前提交
c4bf080315
共有 53 個文件被更改,包括 4025 次插入784 次删除
  1. 6 6
      vendor.conf
  2. 29 5
      vendor/github.com/beorn7/perks/quantile/stream.go
  3. 0 5
      vendor/github.com/prometheus/client_golang/NOTICE
  4. 1 53
      vendor/github.com/prometheus/client_golang/prometheus/README.md
  5. 26 26
      vendor/github.com/prometheus/client_golang/prometheus/collector.go
  6. 14 15
      vendor/github.com/prometheus/client_golang/prometheus/counter.go
  7. 13 0
      vendor/github.com/prometheus/client_golang/prometheus/desc.go
  8. 131 61
      vendor/github.com/prometheus/client_golang/prometheus/doc.go
  9. 16 16
      vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
  10. 4 8
      vendor/github.com/prometheus/client_golang/prometheus/gauge.go
  11. 1 1
      vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
  12. 10 14
      vendor/github.com/prometheus/client_golang/prometheus/histogram.go
  13. 112 3
      vendor/github.com/prometheus/client_golang/prometheus/http.go
  14. 17 17
      vendor/github.com/prometheus/client_golang/prometheus/metric.go
  15. 2 2
      vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
  16. 0 65
      vendor/github.com/prometheus/client_golang/prometheus/push.go
  17. 517 313
      vendor/github.com/prometheus/client_golang/prometheus/registry.go
  18. 12 16
      vendor/github.com/prometheus/client_golang/prometheus/summary.go
  19. 4 8
      vendor/github.com/prometheus/client_golang/prometheus/untyped.go
  20. 4 4
      vendor/github.com/prometheus/client_golang/prometheus/value.go
  21. 199 44
      vendor/github.com/prometheus/client_golang/prometheus/vec.go
  22. 2 2
      vendor/github.com/prometheus/common/README.md
  23. 32 15
      vendor/github.com/prometheus/common/expfmt/decode.go
  24. 5 7
      vendor/github.com/prometheus/common/expfmt/expfmt.go
  25. 5 2
      vendor/github.com/prometheus/common/expfmt/text_create.go
  26. 7 3
      vendor/github.com/prometheus/common/expfmt/text_parse.go
  27. 8 4
      vendor/github.com/prometheus/common/model/labels.go
  28. 1 1
      vendor/github.com/prometheus/common/model/labelset.go
  29. 8 3
      vendor/github.com/prometheus/common/model/metric.go
  30. 2 2
      vendor/github.com/prometheus/common/model/silence.go
  31. 16 1
      vendor/github.com/prometheus/common/model/time.go
  32. 19 6
      vendor/github.com/prometheus/common/model/value.go
  33. 1 0
      vendor/github.com/prometheus/procfs/README.md
  34. 95 0
      vendor/github.com/prometheus/procfs/buddyinfo.go
  35. 49 0
      vendor/github.com/prometheus/procfs/fs.go
  36. 46 0
      vendor/github.com/prometheus/procfs/internal/util/parse.go
  37. 52 17
      vendor/github.com/prometheus/procfs/ipvs.go
  38. 13 0
      vendor/github.com/prometheus/procfs/mdstat.go
  39. 569 0
      vendor/github.com/prometheus/procfs/mountstats.go
  40. 216 0
      vendor/github.com/prometheus/procfs/net_dev.go
  41. 263 0
      vendor/github.com/prometheus/procfs/nfs/nfs.go
  42. 317 0
      vendor/github.com/prometheus/procfs/nfs/parse.go
  43. 67 0
      vendor/github.com/prometheus/procfs/nfs/parse_nfs.go
  44. 89 0
      vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go
  45. 27 1
      vendor/github.com/prometheus/procfs/proc.go
  46. 14 4
      vendor/github.com/prometheus/procfs/proc_io.go
  47. 32 19
      vendor/github.com/prometheus/procfs/proc_limits.go
  48. 68 0
      vendor/github.com/prometheus/procfs/proc_ns.go
  49. 13 0
      vendor/github.com/prometheus/procfs/proc_stat.go
  50. 191 15
      vendor/github.com/prometheus/procfs/stat.go
  51. 187 0
      vendor/github.com/prometheus/procfs/xfrm.go
  52. 330 0
      vendor/github.com/prometheus/procfs/xfs/parse.go
  53. 163 0
      vendor/github.com/prometheus/procfs/xfs/xfs.go

+ 6 - 6
vendor.conf

@@ -140,13 +140,13 @@ golang.org/x/time fbb02b2291d28baffd63558aa44b4b56f178d650
 github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
 github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
 github.com/hashicorp/go-immutable-radix 826af9ccf0feeee615d546d69b11f8e98da8c8f1 git://github.com/tonistiigi/go-immutable-radix.git
 github.com/hashicorp/go-immutable-radix 826af9ccf0feeee615d546d69b11f8e98da8c8f1 git://github.com/tonistiigi/go-immutable-radix.git
 github.com/hashicorp/golang-lru 0fb14efe8c47ae851c0034ed7a448854d3d34cf3
 github.com/hashicorp/golang-lru 0fb14efe8c47ae851c0034ed7a448854d3d34cf3
-github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
+github.com/coreos/pkg v3
 github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
 github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
-github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
-github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
-github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
-github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
-github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/prometheus/client_golang v0.8.0
+github.com/beorn7/perks 3a771d992973f24aa725d07868b467d1ddfceaf
+github.com/prometheus/client_model 6f3806018612930941127f2a7c6c453ba2c527d2
+github.com/prometheus/common 7600349dcfe1abd18d72d3a1770870d9800a7801
+github.com/prometheus/procfs 7d6f385de8bea29190f15ba9931442a0eaef9af7
 github.com/matttproud/golang_protobuf_extensions v1.0.0
 github.com/matttproud/golang_protobuf_extensions v1.0.0
 github.com/pkg/errors 645ef00459ed84a119197bfb8d8205042c6df63d # v0.8.0
 github.com/pkg/errors 645ef00459ed84a119197bfb8d8205042c6df63d # v0.8.0
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0

+ 29 - 5
vendor/github.com/beorn7/perks/quantile/stream.go

@@ -77,15 +77,20 @@ func NewHighBiased(epsilon float64) *Stream {
 // is guaranteed to be within (Quantile±Epsilon).
 // is guaranteed to be within (Quantile±Epsilon).
 //
 //
 // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties.
 // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties.
-func NewTargeted(targets map[float64]float64) *Stream {
+func NewTargeted(targetMap map[float64]float64) *Stream {
+	// Convert map to slice to avoid slow iterations on a map.
+	// ƒ is called on the hot path, so converting the map to a slice
+	// beforehand results in significant CPU savings.
+	targets := targetMapToSlice(targetMap)
+
 	ƒ := func(s *stream, r float64) float64 {
 	ƒ := func(s *stream, r float64) float64 {
 		var m = math.MaxFloat64
 		var m = math.MaxFloat64
 		var f float64
 		var f float64
-		for quantile, epsilon := range targets {
-			if quantile*s.n <= r {
-				f = (2 * epsilon * r) / quantile
+		for _, t := range targets {
+			if t.quantile*s.n <= r {
+				f = (2 * t.epsilon * r) / t.quantile
 			} else {
 			} else {
-				f = (2 * epsilon * (s.n - r)) / (1 - quantile)
+				f = (2 * t.epsilon * (s.n - r)) / (1 - t.quantile)
 			}
 			}
 			if f < m {
 			if f < m {
 				m = f
 				m = f
@@ -96,6 +101,25 @@ func NewTargeted(targets map[float64]float64) *Stream {
 	return newStream(ƒ)
 	return newStream(ƒ)
 }
 }
 
 
+type target struct {
+	quantile float64
+	epsilon  float64
+}
+
+func targetMapToSlice(targetMap map[float64]float64) []target {
+	targets := make([]target, 0, len(targetMap))
+
+	for quantile, epsilon := range targetMap {
+		t := target{
+			quantile: quantile,
+			epsilon:  epsilon,
+		}
+		targets = append(targets, t)
+	}
+
+	return targets
+}
+
 // Stream computes quantiles for a stream of float64s. It is not thread-safe by
 // Stream computes quantiles for a stream of float64s. It is not thread-safe by
 // design. Take care when using across multiple goroutines.
 // design. Take care when using across multiple goroutines.
 type Stream struct {
 type Stream struct {

+ 0 - 5
vendor/github.com/prometheus/client_golang/NOTICE

@@ -7,11 +7,6 @@ SoundCloud Ltd. (http://soundcloud.com/).
 
 
 The following components are included in this product:
 The following components are included in this product:
 
 
-goautoneg
-http://bitbucket.org/ww/goautoneg
-Copyright 2011, Open Knowledge Foundation Ltd.
-See README.txt for license details.
-
 perks - a fork of https://github.com/bmizerany/perks
 perks - a fork of https://github.com/bmizerany/perks
 https://github.com/beorn7/perks
 https://github.com/beorn7/perks
 Copyright 2013-2015 Blake Mizerany, Björn Rabenstein
 Copyright 2013-2015 Blake Mizerany, Björn Rabenstein

+ 1 - 53
vendor/github.com/prometheus/client_golang/prometheus/README.md

@@ -1,53 +1 @@
-# Overview
-This is the [Prometheus](http://www.prometheus.io) telemetric
-instrumentation client [Go](http://golang.org) client library.  It
-enable authors to define process-space metrics for their servers and
-expose them through a web service interface for extraction,
-aggregation, and a whole slew of other post processing techniques.
-
-# Installing
-    $ go get github.com/prometheus/client_golang/prometheus
-
-# Example
-```go
-package main
-
-import (
-	"net/http"
-
-	"github.com/prometheus/client_golang/prometheus"
-)
-
-var (
-	indexed = prometheus.NewCounter(prometheus.CounterOpts{
-		Namespace: "my_company",
-		Subsystem: "indexer",
-		Name:      "documents_indexed",
-		Help:      "The number of documents indexed.",
-	})
-	size = prometheus.NewGauge(prometheus.GaugeOpts{
-		Namespace: "my_company",
-		Subsystem: "storage",
-		Name:      "documents_total_size_bytes",
-		Help:      "The total size of all documents in the storage.",
-	})
-)
-
-func main() {
-	http.Handle("/metrics", prometheus.Handler())
-
-	indexed.Inc()
-	size.Set(5)
-
-	http.ListenAndServe(":8080", nil)
-}
-
-func init() {
-	prometheus.MustRegister(indexed)
-	prometheus.MustRegister(size)
-}
-```
-
-# Documentation
-
-[![GoDoc](https://godoc.org/github.com/prometheus/client_golang?status.png)](https://godoc.org/github.com/prometheus/client_golang)
+See [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus).

+ 26 - 26
vendor/github.com/prometheus/client_golang/prometheus/collector.go

@@ -15,15 +15,15 @@ package prometheus
 
 
 // Collector is the interface implemented by anything that can be used by
 // Collector is the interface implemented by anything that can be used by
 // Prometheus to collect metrics. A Collector has to be registered for
 // Prometheus to collect metrics. A Collector has to be registered for
-// collection. See Register, MustRegister, RegisterOrGet, and MustRegisterOrGet.
+// collection. See Registerer.Register.
 //
 //
-// The stock metrics provided by this package (like Gauge, Counter, Summary) are
-// also Collectors (which only ever collect one metric, namely itself). An
-// implementer of Collector may, however, collect multiple metrics in a
-// coordinated fashion and/or create metrics on the fly. Examples for collectors
-// already implemented in this library are the metric vectors (i.e. collection
-// of multiple instances of the same Metric but with different label values)
-// like GaugeVec or SummaryVec, and the ExpvarCollector.
+// The stock metrics provided by this package (Gauge, Counter, Summary,
+// Histogram, Untyped) are also Collectors (which only ever collect one metric,
+// namely itself). An implementer of Collector may, however, collect multiple
+// metrics in a coordinated fashion and/or create metrics on the fly. Examples
+// for collectors already implemented in this library are the metric vectors
+// (i.e. collection of multiple instances of the same Metric but with different
+// label values) like GaugeVec or SummaryVec, and the ExpvarCollector.
 type Collector interface {
 type Collector interface {
 	// Describe sends the super-set of all possible descriptors of metrics
 	// Describe sends the super-set of all possible descriptors of metrics
 	// collected by this Collector to the provided channel and returns once
 	// collected by this Collector to the provided channel and returns once
@@ -37,39 +37,39 @@ type Collector interface {
 	// executing this method, it must send an invalid descriptor (created
 	// executing this method, it must send an invalid descriptor (created
 	// with NewInvalidDesc) to signal the error to the registry.
 	// with NewInvalidDesc) to signal the error to the registry.
 	Describe(chan<- *Desc)
 	Describe(chan<- *Desc)
-	// Collect is called by Prometheus when collecting metrics. The
-	// implementation sends each collected metric via the provided channel
-	// and returns once the last metric has been sent. The descriptor of
-	// each sent metric is one of those returned by Describe. Returned
-	// metrics that share the same descriptor must differ in their variable
-	// label values. This method may be called concurrently and must
-	// therefore be implemented in a concurrency safe way. Blocking occurs
-	// at the expense of total performance of rendering all registered
-	// metrics. Ideally, Collector implementations support concurrent
-	// readers.
+	// Collect is called by the Prometheus registry when collecting
+	// metrics. The implementation sends each collected metric via the
+	// provided channel and returns once the last metric has been sent. The
+	// descriptor of each sent metric is one of those returned by
+	// Describe. Returned metrics that share the same descriptor must differ
+	// in their variable label values. This method may be called
+	// concurrently and must therefore be implemented in a concurrency safe
+	// way. Blocking occurs at the expense of total performance of rendering
+	// all registered metrics. Ideally, Collector implementations support
+	// concurrent readers.
 	Collect(chan<- Metric)
 	Collect(chan<- Metric)
 }
 }
 
 
-// SelfCollector implements Collector for a single Metric so that that the
-// Metric collects itself. Add it as an anonymous field to a struct that
-// implements Metric, and call Init with the Metric itself as an argument.
-type SelfCollector struct {
+// selfCollector implements Collector for a single Metric so that the Metric
+// collects itself. Add it as an anonymous field to a struct that implements
+// Metric, and call init with the Metric itself as an argument.
+type selfCollector struct {
 	self Metric
 	self Metric
 }
 }
 
 
-// Init provides the SelfCollector with a reference to the metric it is supposed
+// init provides the selfCollector with a reference to the metric it is supposed
 // to collect. It is usually called within the factory function to create a
 // to collect. It is usually called within the factory function to create a
 // metric. See example.
 // metric. See example.
-func (c *SelfCollector) Init(self Metric) {
+func (c *selfCollector) init(self Metric) {
 	c.self = self
 	c.self = self
 }
 }
 
 
 // Describe implements Collector.
 // Describe implements Collector.
-func (c *SelfCollector) Describe(ch chan<- *Desc) {
+func (c *selfCollector) Describe(ch chan<- *Desc) {
 	ch <- c.self.Desc()
 	ch <- c.self.Desc()
 }
 }
 
 
 // Collect implements Collector.
 // Collect implements Collector.
-func (c *SelfCollector) Collect(ch chan<- Metric) {
+func (c *selfCollector) Collect(ch chan<- Metric) {
 	ch <- c.self
 	ch <- c.self
 }
 }

+ 14 - 15
vendor/github.com/prometheus/client_golang/prometheus/counter.go

@@ -35,6 +35,9 @@ type Counter interface {
 	// Prometheus metric. Do not use it for regular handling of a
 	// Prometheus metric. Do not use it for regular handling of a
 	// Prometheus counter (as it can be used to break the contract of
 	// Prometheus counter (as it can be used to break the contract of
 	// monotonically increasing values).
 	// monotonically increasing values).
+	//
+	// Deprecated: Use NewConstMetric to create a counter for an external
+	// value. A Counter should never be set.
 	Set(float64)
 	Set(float64)
 	// Inc increments the counter by 1.
 	// Inc increments the counter by 1.
 	Inc()
 	Inc()
@@ -55,7 +58,7 @@ func NewCounter(opts CounterOpts) Counter {
 		opts.ConstLabels,
 		opts.ConstLabels,
 	)
 	)
 	result := &counter{value: value{desc: desc, valType: CounterValue, labelPairs: desc.constLabelPairs}}
 	result := &counter{value: value{desc: desc, valType: CounterValue, labelPairs: desc.constLabelPairs}}
-	result.Init(result) // Init self-collection.
+	result.init(result) // Init self-collection.
 	return result
 	return result
 }
 }
 
 
@@ -79,7 +82,7 @@ func (c *counter) Add(v float64) {
 // CounterVec embeds MetricVec. See there for a full list of methods with
 // CounterVec embeds MetricVec. See there for a full list of methods with
 // detailed documentation.
 // detailed documentation.
 type CounterVec struct {
 type CounterVec struct {
-	MetricVec
+	*MetricVec
 }
 }
 
 
 // NewCounterVec creates a new CounterVec based on the provided CounterOpts and
 // NewCounterVec creates a new CounterVec based on the provided CounterOpts and
@@ -93,19 +96,15 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
 		opts.ConstLabels,
 		opts.ConstLabels,
 	)
 	)
 	return &CounterVec{
 	return &CounterVec{
-		MetricVec: MetricVec{
-			children: map[uint64]Metric{},
-			desc:     desc,
-			newMetric: func(lvs ...string) Metric {
-				result := &counter{value: value{
-					desc:       desc,
-					valType:    CounterValue,
-					labelPairs: makeLabelPairs(desc, lvs),
-				}}
-				result.Init(result) // Init self-collection.
-				return result
-			},
-		},
+		MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+			result := &counter{value: value{
+				desc:       desc,
+				valType:    CounterValue,
+				labelPairs: makeLabelPairs(desc, lvs),
+			}}
+			result.init(result) // Init self-collection.
+			return result
+		}),
 	}
 	}
 }
 }
 
 

+ 13 - 0
vendor/github.com/prometheus/client_golang/prometheus/desc.go

@@ -1,3 +1,16 @@
+// Copyright 2016 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 prometheus
 package prometheus
 
 
 import (
 import (

+ 131 - 61
vendor/github.com/prometheus/client_golang/prometheus/doc.go

@@ -11,18 +11,17 @@
 // See the License for the specific language governing permissions and
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // limitations under the License.
 
 
-// Package prometheus provides embeddable metric primitives for servers and
-// standardized exposition of telemetry through a web services interface.
+// Package prometheus provides metrics primitives to instrument code for
+// monitoring. It also offers a registry for metrics. Sub-packages allow to
+// expose the registered metrics via HTTP (package promhttp) or push them to a
+// Pushgateway (package push).
 //
 //
 // All exported functions and methods are safe to be used concurrently unless
 // All exported functions and methods are safe to be used concurrently unless
-// specified otherwise.
+//specified otherwise.
 //
 //
-// To expose metrics registered with the Prometheus registry, an HTTP server
-// needs to know about the Prometheus handler. The usual endpoint is "/metrics".
+// A Basic Example
 //
 //
-//     http.Handle("/metrics", prometheus.Handler())
-//
-// As a starting point a very basic usage example:
+// As a starting point, a very basic usage example:
 //
 //
 //    package main
 //    package main
 //
 //
@@ -30,6 +29,7 @@
 //    	"net/http"
 //    	"net/http"
 //
 //
 //    	"github.com/prometheus/client_golang/prometheus"
 //    	"github.com/prometheus/client_golang/prometheus"
+//    	"github.com/prometheus/client_golang/prometheus/promhttp"
 //    )
 //    )
 //
 //
 //    var (
 //    var (
@@ -37,75 +37,145 @@
 //    		Name: "cpu_temperature_celsius",
 //    		Name: "cpu_temperature_celsius",
 //    		Help: "Current temperature of the CPU.",
 //    		Help: "Current temperature of the CPU.",
 //    	})
 //    	})
-//    	hdFailures = prometheus.NewCounter(prometheus.CounterOpts{
-//    		Name: "hd_errors_total",
-//    		Help: "Number of hard-disk errors.",
-//    	})
+//    	hdFailures = prometheus.NewCounterVec(
+//    		prometheus.CounterOpts{
+//    			Name: "hd_errors_total",
+//    			Help: "Number of hard-disk errors.",
+//    		},
+//    		[]string{"device"},
+//    	)
 //    )
 //    )
 //
 //
 //    func init() {
 //    func init() {
+//    	// Metrics have to be registered to be exposed:
 //    	prometheus.MustRegister(cpuTemp)
 //    	prometheus.MustRegister(cpuTemp)
 //    	prometheus.MustRegister(hdFailures)
 //    	prometheus.MustRegister(hdFailures)
 //    }
 //    }
 //
 //
 //    func main() {
 //    func main() {
 //    	cpuTemp.Set(65.3)
 //    	cpuTemp.Set(65.3)
-//    	hdFailures.Inc()
+//    	hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc()
 //
 //
-//    	http.Handle("/metrics", prometheus.Handler())
+//    	// The Handler function provides a default handler to expose metrics
+//    	// via an HTTP server. "/metrics" is the usual endpoint for that.
+//    	http.Handle("/metrics", promhttp.Handler())
 //    	http.ListenAndServe(":8080", nil)
 //    	http.ListenAndServe(":8080", nil)
 //    }
 //    }
 //
 //
 //
 //
-// This is a complete program that exports two metrics, a Gauge and a Counter.
-// It also exports some stats about the HTTP usage of the /metrics
-// endpoint. (See the Handler function for more detail.)
+// This is a complete program that exports two metrics, a Gauge and a Counter,
+// the latter with a label attached to turn it into a (one-dimensional) vector.
+//
+// Metrics
 //
 //
-// Two more advanced metric types are the Summary and Histogram. A more
-// thorough description of metric types can be found in the prometheus docs:
+// The number of exported identifiers in this package might appear a bit
+// overwhelming. Hovever, in addition to the basic plumbing shown in the example
+// above, you only need to understand the different metric types and their
+// vector versions for basic usage.
+//
+// Above, you have already touched the Counter and the Gauge. There are two more
+// advanced metric types: the Summary and Histogram. A more thorough description
+// of those four metric types can be found in the Prometheus docs:
 // https://prometheus.io/docs/concepts/metric_types/
 // https://prometheus.io/docs/concepts/metric_types/
 //
 //
-// In addition to the fundamental metric types Gauge, Counter, Summary, and
-// Histogram, a very important part of the Prometheus data model is the
-// partitioning of samples along dimensions called labels, which results in
+// A fifth "type" of metric is Untyped. It behaves like a Gauge, but signals the
+// Prometheus server not to assume anything about its type.
+//
+// In addition to the fundamental metric types Gauge, Counter, Summary,
+// Histogram, and Untyped, a very important part of the Prometheus data model is
+// the partitioning of samples along dimensions called labels, which results in
 // metric vectors. The fundamental types are GaugeVec, CounterVec, SummaryVec,
 // metric vectors. The fundamental types are GaugeVec, CounterVec, SummaryVec,
-// and HistogramVec.
-//
-// Those are all the parts needed for basic usage. Detailed documentation and
-// examples are provided below.
-//
-// Everything else this package offers is essentially for "power users" only. A
-// few pointers to "power user features":
-//
-// All the various ...Opts structs have a ConstLabels field for labels that
-// never change their value (which is only useful under special circumstances,
-// see documentation of the Opts type).
-//
-// The Untyped metric behaves like a Gauge, but signals the Prometheus server
-// not to assume anything about its type.
-//
-// Functions to fine-tune how the metric registry works: EnableCollectChecks,
-// PanicOnCollectError, Register, Unregister, SetMetricFamilyInjectionHook.
-//
-// For custom metric collection, there are two entry points: Custom Metric
-// implementations and custom Collector implementations. A Metric is the
-// fundamental unit in the Prometheus data model: a sample at a point in time
-// together with its meta-data (like its fully-qualified name and any number of
-// pairs of label name and label value) that knows how to marshal itself into a
-// data transfer object (aka DTO, implemented as a protocol buffer). A Collector
-// gets registered with the Prometheus registry and manages the collection of
-// one or more Metrics. Many parts of this package are building blocks for
-// Metrics and Collectors. Desc is the metric descriptor, actually used by all
-// metrics under the hood, and by Collectors to describe the Metrics to be
-// collected, but only to be dealt with by users if they implement their own
-// Metrics or Collectors. To create a Desc, the BuildFQName function will come
-// in handy. Other useful components for Metric and Collector implementation
-// include: LabelPairSorter to sort the DTO version of label pairs,
-// NewConstMetric and MustNewConstMetric to create "throw away" Metrics at
-// collection time, MetricVec to bundle custom Metrics into a metric vector
-// Collector, SelfCollector to make a custom Metric collect itself.
-//
-// A good example for a custom Collector is the ExpVarCollector included in this
-// package, which exports variables exported via the "expvar" package as
-// Prometheus metrics.
+// HistogramVec, and UntypedVec.
+//
+// While only the fundamental metric types implement the Metric interface, both
+// the metrics and their vector versions implement the Collector interface. A
+// Collector manages the collection of a number of Metrics, but for convenience,
+// a Metric can also “collect itself”. Note that Gauge, Counter, Summary,
+// Histogram, and Untyped are interfaces themselves while GaugeVec, CounterVec,
+// SummaryVec, HistogramVec, and UntypedVec are not.
+//
+// To create instances of Metrics and their vector versions, you need a suitable
+// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts,
+// HistogramOpts, or UntypedOpts.
+//
+// Custom Collectors and constant Metrics
+//
+// While you could create your own implementations of Metric, most likely you
+// will only ever implement the Collector interface on your own. At a first
+// glance, a custom Collector seems handy to bundle Metrics for common
+// registration (with the prime example of the different metric vectors above,
+// which bundle all the metrics of the same name but with different labels).
+//
+// There is a more involved use case, too: If you already have metrics
+// available, created outside of the Prometheus context, you don't need the
+// interface of the various Metric types. You essentially want to mirror the
+// existing numbers into Prometheus Metrics during collection. An own
+// implementation of the Collector interface is perfect for that. You can create
+// Metric instances “on the fly” using NewConstMetric, NewConstHistogram, and
+// NewConstSummary (and their respective Must… versions). That will happen in
+// the Collect method. The Describe method has to return separate Desc
+// instances, representative of the “throw-away” metrics to be created
+// later. NewDesc comes in handy to create those Desc instances.
+//
+// The Collector example illustrates the use case. You can also look at the
+// source code of the processCollector (mirroring process metrics), the
+// goCollector (mirroring Go metrics), or the expvarCollector (mirroring expvar
+// metrics) as examples that are used in this package itself.
+//
+// If you just need to call a function to get a single float value to collect as
+// a metric, GaugeFunc, CounterFunc, or UntypedFunc might be interesting
+// shortcuts.
+//
+// Advanced Uses of the Registry
+//
+// While MustRegister is the by far most common way of registering a Collector,
+// sometimes you might want to handle the errors the registration might
+// cause. As suggested by the name, MustRegister panics if an error occurs. With
+// the Register function, the error is returned and can be handled.
+//
+// An error is returned if the registered Collector is incompatible or
+// inconsistent with already registered metrics. The registry aims for
+// consistency of the collected metrics according to the Prometheus data
+// model. Inconsistencies are ideally detected at registration time, not at
+// collect time. The former will usually be detected at start-up time of a
+// program, while the latter will only happen at scrape time, possibly not even
+// on the first scrape if the inconsistency only becomes relevant later. That is
+// the main reason why a Collector and a Metric have to describe themselves to
+// the registry.
+//
+// So far, everything we did operated on the so-called default registry, as it
+// can be found in the global DefaultRegistry variable. With NewRegistry, you
+// can create a custom registry, or you can even implement the Registerer or
+// Gatherer interfaces yourself. The methods Register and Unregister work in
+// the same way on a custom registry as the global functions Register and
+// Unregister on the default registry.
+//
+// There are a number of uses for custom registries: You can use registries
+// with special properties, see NewPedanticRegistry. You can avoid global state,
+// as it is imposed by the DefaultRegistry. You can use multiple registries at
+// the same time to expose different metrics in different ways. You can use
+// separate registries for testing purposes.
+//
+// Also note that the DefaultRegistry comes registered with a Collector for Go
+// runtime metrics (via NewGoCollector) and a Collector for process metrics (via
+// NewProcessCollector). With a custom registry, you are in control and decide
+// yourself about the Collectors to register.
+//
+// HTTP Exposition
+//
+// The Registry implements the Gatherer interface. The caller of the Gather
+// method can then expose the gathered metrics in some way. Usually, the metrics
+// are served via HTTP on the /metrics endpoint. That's happening in the example
+// above. The tools to expose metrics via HTTP are in the promhttp
+// sub-package. (The top-level functions in the prometheus package are
+// deprecated.)
+//
+// Pushing to the Pushgateway
+//
+// Function for pushing to the Pushgateway can be found in the push sub-package.
+//
+// Other Means of Exposition
+//
+// More ways of exposing metrics can easily be added. Sending metrics to
+// Graphite would be an example that will soon be implemented.
 package prometheus
 package prometheus

+ 16 - 16
vendor/github.com/prometheus/client_golang/prometheus/expvar.go → vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go

@@ -18,21 +18,21 @@ import (
 	"expvar"
 	"expvar"
 )
 )
 
 
-// ExpvarCollector collects metrics from the expvar interface. It provides a
-// quick way to expose numeric values that are already exported via expvar as
-// Prometheus metrics. Note that the data models of expvar and Prometheus are
-// fundamentally different, and that the ExpvarCollector is inherently
-// slow. Thus, the ExpvarCollector is probably great for experiments and
-// prototying, but you should seriously consider a more direct implementation of
-// Prometheus metrics for monitoring production systems.
-//
-// Use NewExpvarCollector to create new instances.
-type ExpvarCollector struct {
+type expvarCollector struct {
 	exports map[string]*Desc
 	exports map[string]*Desc
 }
 }
 
 
-// NewExpvarCollector returns a newly allocated ExpvarCollector that still has
-// to be registered with the Prometheus registry.
+// NewExpvarCollector returns a newly allocated expvar Collector that still has
+// to be registered with a Prometheus registry.
+//
+// An expvar Collector collects metrics from the expvar interface. It provides a
+// quick way to expose numeric values that are already exported via expvar as
+// Prometheus metrics. Note that the data models of expvar and Prometheus are
+// fundamentally different, and that the expvar Collector is inherently slower
+// than native Prometheus metrics. Thus, the expvar Collector is probably great
+// for experiments and prototying, but you should seriously consider a more
+// direct implementation of Prometheus metrics for monitoring production
+// systems.
 //
 //
 // The exports map has the following meaning:
 // The exports map has the following meaning:
 //
 //
@@ -59,21 +59,21 @@ type ExpvarCollector struct {
 // sample values.
 // sample values.
 //
 //
 // Anything that does not fit into the scheme above is silently ignored.
 // Anything that does not fit into the scheme above is silently ignored.
-func NewExpvarCollector(exports map[string]*Desc) *ExpvarCollector {
-	return &ExpvarCollector{
+func NewExpvarCollector(exports map[string]*Desc) Collector {
+	return &expvarCollector{
 		exports: exports,
 		exports: exports,
 	}
 	}
 }
 }
 
 
 // Describe implements Collector.
 // Describe implements Collector.
-func (e *ExpvarCollector) Describe(ch chan<- *Desc) {
+func (e *expvarCollector) Describe(ch chan<- *Desc) {
 	for _, desc := range e.exports {
 	for _, desc := range e.exports {
 		ch <- desc
 		ch <- desc
 	}
 	}
 }
 }
 
 
 // Collect implements Collector.
 // Collect implements Collector.
-func (e *ExpvarCollector) Collect(ch chan<- Metric) {
+func (e *expvarCollector) Collect(ch chan<- Metric) {
 	for name, desc := range e.exports {
 	for name, desc := range e.exports {
 		var m Metric
 		var m Metric
 		expVar := expvar.Get(name)
 		expVar := expvar.Get(name)

+ 4 - 8
vendor/github.com/prometheus/client_golang/prometheus/gauge.go

@@ -58,7 +58,7 @@ func NewGauge(opts GaugeOpts) Gauge {
 // (e.g. number of operations queued, partitioned by user and operation
 // (e.g. number of operations queued, partitioned by user and operation
 // type). Create instances with NewGaugeVec.
 // type). Create instances with NewGaugeVec.
 type GaugeVec struct {
 type GaugeVec struct {
-	MetricVec
+	*MetricVec
 }
 }
 
 
 // NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
 // NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
@@ -72,13 +72,9 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
 		opts.ConstLabels,
 		opts.ConstLabels,
 	)
 	)
 	return &GaugeVec{
 	return &GaugeVec{
-		MetricVec: MetricVec{
-			children: map[uint64]Metric{},
-			desc:     desc,
-			newMetric: func(lvs ...string) Metric {
-				return newValue(desc, GaugeValue, 0, lvs...)
-			},
-		},
+		MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+			return newValue(desc, GaugeValue, 0, lvs...)
+		}),
 	}
 	}
 }
 }
 
 

+ 1 - 1
vendor/github.com/prometheus/client_golang/prometheus/go_collector.go

@@ -17,7 +17,7 @@ type goCollector struct {
 
 
 // NewGoCollector returns a collector which exports metrics about the current
 // NewGoCollector returns a collector which exports metrics about the current
 // go process.
 // go process.
-func NewGoCollector() *goCollector {
+func NewGoCollector() Collector {
 	return &goCollector{
 	return &goCollector{
 		goroutines: NewGauge(GaugeOpts{
 		goroutines: NewGauge(GaugeOpts{
 			Namespace: "go",
 			Namespace: "go",

+ 10 - 14
vendor/github.com/prometheus/client_golang/prometheus/histogram.go

@@ -51,11 +51,11 @@ type Histogram interface {
 // bucket of a histogram ("le" -> "less or equal").
 // bucket of a histogram ("le" -> "less or equal").
 const bucketLabel = "le"
 const bucketLabel = "le"
 
 
+// DefBuckets are the default Histogram buckets. The default buckets are
+// tailored to broadly measure the response time (in seconds) of a network
+// service. Most likely, however, you will be required to define buckets
+// customized to your use case.
 var (
 var (
-	// DefBuckets are the default Histogram buckets. The default buckets are
-	// tailored to broadly measure the response time (in seconds) of a
-	// network service. Most likely, however, you will be required to define
-	// buckets customized to your use case.
 	DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
 	DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
 
 
 	errBucketLabelNotAllowed = fmt.Errorf(
 	errBucketLabelNotAllowed = fmt.Errorf(
@@ -210,7 +210,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
 	// Finally we know the final length of h.upperBounds and can make counts.
 	// Finally we know the final length of h.upperBounds and can make counts.
 	h.counts = make([]uint64, len(h.upperBounds))
 	h.counts = make([]uint64, len(h.upperBounds))
 
 
-	h.Init(h) // Init self-collection.
+	h.init(h) // Init self-collection.
 	return h
 	return h
 }
 }
 
 
@@ -222,7 +222,7 @@ type histogram struct {
 	sumBits uint64
 	sumBits uint64
 	count   uint64
 	count   uint64
 
 
-	SelfCollector
+	selfCollector
 	// Note that there is no mutex required.
 	// Note that there is no mutex required.
 
 
 	desc *Desc
 	desc *Desc
@@ -287,7 +287,7 @@ func (h *histogram) Write(out *dto.Metric) error {
 // (e.g. HTTP request latencies, partitioned by status code and method). Create
 // (e.g. HTTP request latencies, partitioned by status code and method). Create
 // instances with NewHistogramVec.
 // instances with NewHistogramVec.
 type HistogramVec struct {
 type HistogramVec struct {
-	MetricVec
+	*MetricVec
 }
 }
 
 
 // NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and
 // NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and
@@ -301,13 +301,9 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
 		opts.ConstLabels,
 		opts.ConstLabels,
 	)
 	)
 	return &HistogramVec{
 	return &HistogramVec{
-		MetricVec: MetricVec{
-			children: map[uint64]Metric{},
-			desc:     desc,
-			newMetric: func(lvs ...string) Metric {
-				return newHistogram(desc, opts, lvs...)
-			},
-		},
+		MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+			return newHistogram(desc, opts, lvs...)
+		}),
 	}
 	}
 }
 }
 
 

+ 112 - 3
vendor/github.com/prometheus/client_golang/prometheus/http.go

@@ -15,14 +15,114 @@ package prometheus
 
 
 import (
 import (
 	"bufio"
 	"bufio"
+	"bytes"
+	"compress/gzip"
+	"fmt"
 	"io"
 	"io"
 	"net"
 	"net"
 	"net/http"
 	"net/http"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
+	"sync"
 	"time"
 	"time"
+
+	"github.com/prometheus/common/expfmt"
+)
+
+// TODO(beorn7): Remove this whole file. It is a partial mirror of
+// promhttp/http.go (to avoid circular import chains) where everything HTTP
+// related should live. The functions here are just for avoiding
+// breakage. Everything is deprecated.
+
+const (
+	contentTypeHeader     = "Content-Type"
+	contentLengthHeader   = "Content-Length"
+	contentEncodingHeader = "Content-Encoding"
+	acceptEncodingHeader  = "Accept-Encoding"
 )
 )
 
 
+var bufPool sync.Pool
+
+func getBuf() *bytes.Buffer {
+	buf := bufPool.Get()
+	if buf == nil {
+		return &bytes.Buffer{}
+	}
+	return buf.(*bytes.Buffer)
+}
+
+func giveBuf(buf *bytes.Buffer) {
+	buf.Reset()
+	bufPool.Put(buf)
+}
+
+// Handler returns an HTTP handler for the DefaultGatherer. It is
+// already instrumented with InstrumentHandler (using "prometheus" as handler
+// name).
+//
+// Deprecated: Please note the issues described in the doc comment of
+// InstrumentHandler. You might want to consider using promhttp.Handler instead
+// (which is non instrumented).
+func Handler() http.Handler {
+	return InstrumentHandler("prometheus", UninstrumentedHandler())
+}
+
+// UninstrumentedHandler returns an HTTP handler for the DefaultGatherer.
+//
+// Deprecated: Use promhttp.Handler instead. See there for further documentation.
+func UninstrumentedHandler() http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+		mfs, err := DefaultGatherer.Gather()
+		if err != nil {
+			http.Error(w, "An error has occurred during metrics collection:\n\n"+err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		contentType := expfmt.Negotiate(req.Header)
+		buf := getBuf()
+		defer giveBuf(buf)
+		writer, encoding := decorateWriter(req, buf)
+		enc := expfmt.NewEncoder(writer, contentType)
+		var lastErr error
+		for _, mf := range mfs {
+			if err := enc.Encode(mf); err != nil {
+				lastErr = err
+				http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError)
+				return
+			}
+		}
+		if closer, ok := writer.(io.Closer); ok {
+			closer.Close()
+		}
+		if lastErr != nil && buf.Len() == 0 {
+			http.Error(w, "No metrics encoded, last error:\n\n"+err.Error(), http.StatusInternalServerError)
+			return
+		}
+		header := w.Header()
+		header.Set(contentTypeHeader, string(contentType))
+		header.Set(contentLengthHeader, fmt.Sprint(buf.Len()))
+		if encoding != "" {
+			header.Set(contentEncodingHeader, encoding)
+		}
+		w.Write(buf.Bytes())
+	})
+}
+
+// decorateWriter wraps a writer to handle gzip compression if requested.  It
+// returns the decorated writer and the appropriate "Content-Encoding" header
+// (which is empty if no compression is enabled).
+func decorateWriter(request *http.Request, writer io.Writer) (io.Writer, string) {
+	header := request.Header.Get(acceptEncodingHeader)
+	parts := strings.Split(header, ",")
+	for _, part := range parts {
+		part := strings.TrimSpace(part)
+		if part == "gzip" || strings.HasPrefix(part, "gzip;") {
+			return gzip.NewWriter(writer), "gzip"
+		}
+	}
+	return writer, ""
+}
+
 var instLabels = []string{"method", "code"}
 var instLabels = []string{"method", "code"}
 
 
 type nower interface {
 type nower interface {
@@ -58,7 +158,7 @@ func nowSeries(t ...time.Time) nower {
 // value. http_requests_total is a metric vector partitioned by HTTP method
 // value. http_requests_total is a metric vector partitioned by HTTP method
 // (label name "method") and HTTP status code (label name "code").
 // (label name "method") and HTTP status code (label name "code").
 //
 //
-// Note that InstrumentHandler has several issues:
+// Deprecated: InstrumentHandler has several issues:
 //
 //
 // - It uses Summaries rather than Histograms. Summaries are not useful if
 // - It uses Summaries rather than Histograms. Summaries are not useful if
 // aggregation across multiple instances is required.
 // aggregation across multiple instances is required.
@@ -73,8 +173,8 @@ func nowSeries(t ...time.Time) nower {
 // performing such writes.
 // performing such writes.
 //
 //
 // Upcoming versions of this package will provide ways of instrumenting HTTP
 // Upcoming versions of this package will provide ways of instrumenting HTTP
-// handlers that are more flexible and have fewer issues. Consider this function
-// DEPRECATED and prefer direct instrumentation in the meantime.
+// handlers that are more flexible and have fewer issues. Please prefer direct
+// instrumentation in the meantime.
 func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc {
 func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc {
 	return InstrumentHandlerFunc(handlerName, handler.ServeHTTP)
 	return InstrumentHandlerFunc(handlerName, handler.ServeHTTP)
 }
 }
@@ -82,6 +182,9 @@ func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFun
 // InstrumentHandlerFunc wraps the given function for instrumentation. It
 // InstrumentHandlerFunc wraps the given function for instrumentation. It
 // otherwise works in the same way as InstrumentHandler (and shares the same
 // otherwise works in the same way as InstrumentHandler (and shares the same
 // issues).
 // issues).
+//
+// Deprecated: InstrumentHandlerFunc is deprecated for the same reasons as
+// InstrumentHandler is.
 func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
 func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
 	return InstrumentHandlerFuncWithOpts(
 	return InstrumentHandlerFuncWithOpts(
 		SummaryOpts{
 		SummaryOpts{
@@ -117,6 +220,9 @@ func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWri
 // cannot use SummaryOpts. Instead, a CounterOpts struct is created internally,
 // cannot use SummaryOpts. Instead, a CounterOpts struct is created internally,
 // and all its fields are set to the equally named fields in the provided
 // and all its fields are set to the equally named fields in the provided
 // SummaryOpts.
 // SummaryOpts.
+//
+// Deprecated: InstrumentHandlerWithOpts is deprecated for the same reasons as
+// InstrumentHandler is.
 func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.HandlerFunc {
 func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.HandlerFunc {
 	return InstrumentHandlerFuncWithOpts(opts, handler.ServeHTTP)
 	return InstrumentHandlerFuncWithOpts(opts, handler.ServeHTTP)
 }
 }
@@ -125,6 +231,9 @@ func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.Hand
 // the same issues) but provides more flexibility (at the cost of a more complex
 // the same issues) but provides more flexibility (at the cost of a more complex
 // call syntax). See InstrumentHandlerWithOpts for details how the provided
 // call syntax). See InstrumentHandlerWithOpts for details how the provided
 // SummaryOpts are used.
 // SummaryOpts are used.
+//
+// Deprecated: InstrumentHandlerFuncWithOpts is deprecated for the same reasons
+// as InstrumentHandler is.
 func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
 func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
 	reqCnt := NewCounterVec(
 	reqCnt := NewCounterVec(
 		CounterOpts{
 		CounterOpts{

+ 17 - 17
vendor/github.com/prometheus/client_golang/prometheus/metric.go

@@ -22,10 +22,8 @@ import (
 const separatorByte byte = 255
 const separatorByte byte = 255
 
 
 // A Metric models a single sample value with its meta data being exported to
 // A Metric models a single sample value with its meta data being exported to
-// Prometheus. Implementers of Metric in this package inclued Gauge, Counter,
-// Untyped, and Summary. Users can implement their own Metric types, but that
-// should be rarely needed. See the example for SelfCollector, which is also an
-// example for a user-implemented Metric.
+// Prometheus. Implementations of Metric in this package are Gauge, Counter,
+// Histogram, Summary, and Untyped.
 type Metric interface {
 type Metric interface {
 	// Desc returns the descriptor for the Metric. This method idempotently
 	// Desc returns the descriptor for the Metric. This method idempotently
 	// returns the same descriptor throughout the lifetime of the
 	// returns the same descriptor throughout the lifetime of the
@@ -36,21 +34,23 @@ type Metric interface {
 	// Write encodes the Metric into a "Metric" Protocol Buffer data
 	// Write encodes the Metric into a "Metric" Protocol Buffer data
 	// transmission object.
 	// transmission object.
 	//
 	//
-	// Implementers of custom Metric types must observe concurrency safety
-	// as reads of this metric may occur at any time, and any blocking
-	// occurs at the expense of total performance of rendering all
-	// registered metrics. Ideally Metric implementations should support
-	// concurrent readers.
+	// Metric implementations must observe concurrency safety as reads of
+	// this metric may occur at any time, and any blocking occurs at the
+	// expense of total performance of rendering all registered
+	// metrics. Ideally, Metric implementations should support concurrent
+	// readers.
 	//
 	//
-	// The Prometheus client library attempts to minimize memory allocations
-	// and will provide a pre-existing reset dto.Metric pointer. Prometheus
-	// may recycle the dto.Metric proto message, so Metric implementations
-	// should just populate the provided dto.Metric and then should not keep
-	// any reference to it.
-	//
-	// While populating dto.Metric, labels must be sorted lexicographically.
-	// (Implementers may find LabelPairSorter useful for that.)
+	// While populating dto.Metric, it is the responsibility of the
+	// implementation to ensure validity of the Metric protobuf (like valid
+	// UTF-8 strings or syntactically valid metric and label names). It is
+	// recommended to sort labels lexicographically. (Implementers may find
+	// LabelPairSorter useful for that.) Callers of Write should still make
+	// sure of sorting if they depend on it.
 	Write(*dto.Metric) error
 	Write(*dto.Metric) error
+	// TODO(beorn7): The original rationale of passing in a pre-allocated
+	// dto.Metric protobuf to save allocations has disappeared. The
+	// signature of this method should be changed to "Write() (*dto.Metric,
+	// error)".
 }
 }
 
 
 // Opts bundles the options for creating most Metric types. Each metric
 // Opts bundles the options for creating most Metric types. Each metric

+ 2 - 2
vendor/github.com/prometheus/client_golang/prometheus/process_collector.go

@@ -28,7 +28,7 @@ type processCollector struct {
 // NewProcessCollector returns a collector which exports the current state of
 // NewProcessCollector returns a collector which exports the current state of
 // process metrics including cpu, memory and file descriptor usage as well as
 // process metrics including cpu, memory and file descriptor usage as well as
 // the process start time for the given process id under the given namespace.
 // the process start time for the given process id under the given namespace.
-func NewProcessCollector(pid int, namespace string) *processCollector {
+func NewProcessCollector(pid int, namespace string) Collector {
 	return NewProcessCollectorPIDFn(
 	return NewProcessCollectorPIDFn(
 		func() (int, error) { return pid, nil },
 		func() (int, error) { return pid, nil },
 		namespace,
 		namespace,
@@ -43,7 +43,7 @@ func NewProcessCollector(pid int, namespace string) *processCollector {
 func NewProcessCollectorPIDFn(
 func NewProcessCollectorPIDFn(
 	pidFn func() (int, error),
 	pidFn func() (int, error),
 	namespace string,
 	namespace string,
-) *processCollector {
+) Collector {
 	c := processCollector{
 	c := processCollector{
 		pidFn:     pidFn,
 		pidFn:     pidFn,
 		collectFn: func(chan<- Metric) {},
 		collectFn: func(chan<- Metric) {},

+ 0 - 65
vendor/github.com/prometheus/client_golang/prometheus/push.go

@@ -1,65 +0,0 @@
-// Copyright 2015 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.
-
-// Copyright (c) 2013, The Prometheus Authors
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be found
-// in the LICENSE file.
-
-package prometheus
-
-// Push triggers a metric collection by the default registry and pushes all
-// collected metrics to the Pushgateway specified by url. See the Pushgateway
-// documentation for detailed implications of the job and instance
-// parameter. instance can be left empty. You can use just host:port or ip:port
-// as url, in which case 'http://' is added automatically. You can also include
-// the schema in the URL. However, do not include the '/metrics/jobs/...' part.
-//
-// Note that all previously pushed metrics with the same job and instance will
-// be replaced with the metrics pushed by this call. (It uses HTTP method 'PUT'
-// to push to the Pushgateway.)
-func Push(job, instance, url string) error {
-	return defRegistry.Push(job, instance, url, "PUT")
-}
-
-// PushAdd works like Push, but only previously pushed metrics with the same
-// name (and the same job and instance) will be replaced. (It uses HTTP method
-// 'POST' to push to the Pushgateway.)
-func PushAdd(job, instance, url string) error {
-	return defRegistry.Push(job, instance, url, "POST")
-}
-
-// PushCollectors works like Push, but it does not collect from the default
-// registry. Instead, it collects from the provided collectors. It is a
-// convenient way to push only a few metrics.
-func PushCollectors(job, instance, url string, collectors ...Collector) error {
-	return pushCollectors(job, instance, url, "PUT", collectors...)
-}
-
-// PushAddCollectors works like PushAdd, but it does not collect from the
-// default registry. Instead, it collects from the provided collectors. It is a
-// convenient way to push only a few metrics.
-func PushAddCollectors(job, instance, url string, collectors ...Collector) error {
-	return pushCollectors(job, instance, url, "POST", collectors...)
-}
-
-func pushCollectors(job, instance, url, method string, collectors ...Collector) error {
-	r := newRegistry()
-	for _, collector := range collectors {
-		if _, err := r.Register(collector); err != nil {
-			return err
-		}
-	}
-	return r.Push(job, instance, url, method)
-}

文件差異過大導致無法顯示
+ 517 - 313
vendor/github.com/prometheus/client_golang/prometheus/registry.go


+ 12 - 16
vendor/github.com/prometheus/client_golang/prometheus/summary.go

@@ -53,8 +53,8 @@ type Summary interface {
 	Observe(float64)
 	Observe(float64)
 }
 }
 
 
+// DefObjectives are the default Summary quantile values.
 var (
 var (
-	// DefObjectives are the default Summary quantile values.
 	DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
 	DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
 
 
 	errQuantileLabelNotAllowed = fmt.Errorf(
 	errQuantileLabelNotAllowed = fmt.Errorf(
@@ -139,11 +139,11 @@ type SummaryOpts struct {
 	BufCap uint32
 	BufCap uint32
 }
 }
 
 
-// TODO: Great fuck-up with the sliding-window decay algorithm... The Merge
-// method of perk/quantile is actually not working as advertised - and it might
-// be unfixable, as the underlying algorithm is apparently not capable of
-// merging summaries in the first place. To avoid using Merge, we are currently
-// adding observations to _each_ age bucket, i.e. the effort to add a sample is
+// Great fuck-up with the sliding-window decay algorithm... The Merge method of
+// perk/quantile is actually not working as advertised - and it might be
+// unfixable, as the underlying algorithm is apparently not capable of merging
+// summaries in the first place. To avoid using Merge, we are currently adding
+// observations to _each_ age bucket, i.e. the effort to add a sample is
 // essentially multiplied by the number of age buckets. When rotating age
 // essentially multiplied by the number of age buckets. When rotating age
 // buckets, we empty the previous head stream. On scrape time, we simply take
 // buckets, we empty the previous head stream. On scrape time, we simply take
 // the quantiles from the head stream (no merging required). Result: More effort
 // the quantiles from the head stream (no merging required). Result: More effort
@@ -227,12 +227,12 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
 	}
 	}
 	sort.Float64s(s.sortedObjectives)
 	sort.Float64s(s.sortedObjectives)
 
 
-	s.Init(s) // Init self-collection.
+	s.init(s) // Init self-collection.
 	return s
 	return s
 }
 }
 
 
 type summary struct {
 type summary struct {
-	SelfCollector
+	selfCollector
 
 
 	bufMtx sync.Mutex // Protects hotBuf and hotBufExpTime.
 	bufMtx sync.Mutex // Protects hotBuf and hotBufExpTime.
 	mtx    sync.Mutex // Protects every other moving part.
 	mtx    sync.Mutex // Protects every other moving part.
@@ -390,7 +390,7 @@ func (s quantSort) Less(i, j int) bool {
 // (e.g. HTTP request latencies, partitioned by status code and method). Create
 // (e.g. HTTP request latencies, partitioned by status code and method). Create
 // instances with NewSummaryVec.
 // instances with NewSummaryVec.
 type SummaryVec struct {
 type SummaryVec struct {
-	MetricVec
+	*MetricVec
 }
 }
 
 
 // NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and
 // NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and
@@ -404,13 +404,9 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
 		opts.ConstLabels,
 		opts.ConstLabels,
 	)
 	)
 	return &SummaryVec{
 	return &SummaryVec{
-		MetricVec: MetricVec{
-			children: map[uint64]Metric{},
-			desc:     desc,
-			newMetric: func(lvs ...string) Metric {
-				return newSummary(desc, opts, lvs...)
-			},
-		},
+		MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+			return newSummary(desc, opts, lvs...)
+		}),
 	}
 	}
 }
 }
 
 

+ 4 - 8
vendor/github.com/prometheus/client_golang/prometheus/untyped.go

@@ -56,7 +56,7 @@ func NewUntyped(opts UntypedOpts) Untyped {
 // labels. This is used if you want to count the same thing partitioned by
 // labels. This is used if you want to count the same thing partitioned by
 // various dimensions. Create instances with NewUntypedVec.
 // various dimensions. Create instances with NewUntypedVec.
 type UntypedVec struct {
 type UntypedVec struct {
-	MetricVec
+	*MetricVec
 }
 }
 
 
 // NewUntypedVec creates a new UntypedVec based on the provided UntypedOpts and
 // NewUntypedVec creates a new UntypedVec based on the provided UntypedOpts and
@@ -70,13 +70,9 @@ func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec {
 		opts.ConstLabels,
 		opts.ConstLabels,
 	)
 	)
 	return &UntypedVec{
 	return &UntypedVec{
-		MetricVec: MetricVec{
-			children: map[uint64]Metric{},
-			desc:     desc,
-			newMetric: func(lvs ...string) Metric {
-				return newValue(desc, UntypedValue, 0, lvs...)
-			},
-		},
+		MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
+			return newValue(desc, UntypedValue, 0, lvs...)
+		}),
 	}
 	}
 }
 }
 
 

+ 4 - 4
vendor/github.com/prometheus/client_golang/prometheus/value.go

@@ -48,7 +48,7 @@ type value struct {
 	// operations.  http://golang.org/pkg/sync/atomic/#pkg-note-BUG
 	// operations.  http://golang.org/pkg/sync/atomic/#pkg-note-BUG
 	valBits uint64
 	valBits uint64
 
 
-	SelfCollector
+	selfCollector
 
 
 	desc       *Desc
 	desc       *Desc
 	valType    ValueType
 	valType    ValueType
@@ -68,7 +68,7 @@ func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...strin
 		valBits:    math.Float64bits(val),
 		valBits:    math.Float64bits(val),
 		labelPairs: makeLabelPairs(desc, labelValues),
 		labelPairs: makeLabelPairs(desc, labelValues),
 	}
 	}
-	result.Init(result)
+	result.init(result)
 	return result
 	return result
 }
 }
 
 
@@ -113,7 +113,7 @@ func (v *value) Write(out *dto.Metric) error {
 // library to back the implementations of CounterFunc, GaugeFunc, and
 // library to back the implementations of CounterFunc, GaugeFunc, and
 // UntypedFunc.
 // UntypedFunc.
 type valueFunc struct {
 type valueFunc struct {
-	SelfCollector
+	selfCollector
 
 
 	desc       *Desc
 	desc       *Desc
 	valType    ValueType
 	valType    ValueType
@@ -134,7 +134,7 @@ func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *val
 		function:   function,
 		function:   function,
 		labelPairs: makeLabelPairs(desc, nil),
 		labelPairs: makeLabelPairs(desc, nil),
 	}
 	}
-	result.Init(result)
+	result.init(result)
 	return result
 	return result
 }
 }
 
 

+ 199 - 44
vendor/github.com/prometheus/client_golang/prometheus/vec.go

@@ -16,6 +16,8 @@ package prometheus
 import (
 import (
 	"fmt"
 	"fmt"
 	"sync"
 	"sync"
+
+	"github.com/prometheus/common/model"
 )
 )
 
 
 // MetricVec is a Collector to bundle metrics of the same name that
 // MetricVec is a Collector to bundle metrics of the same name that
@@ -25,10 +27,31 @@ import (
 // provided in this package.
 // provided in this package.
 type MetricVec struct {
 type MetricVec struct {
 	mtx      sync.RWMutex // Protects the children.
 	mtx      sync.RWMutex // Protects the children.
-	children map[uint64]Metric
+	children map[uint64][]metricWithLabelValues
 	desc     *Desc
 	desc     *Desc
 
 
-	newMetric func(labelValues ...string) Metric
+	newMetric   func(labelValues ...string) Metric
+	hashAdd     func(h uint64, s string) uint64 // replace hash function for testing collision handling
+	hashAddByte func(h uint64, b byte) uint64
+}
+
+// newMetricVec returns an initialized MetricVec. The concrete value is
+// returned for embedding into another struct.
+func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec {
+	return &MetricVec{
+		children:    map[uint64][]metricWithLabelValues{},
+		desc:        desc,
+		newMetric:   newMetric,
+		hashAdd:     hashAdd,
+		hashAddByte: hashAddByte,
+	}
+}
+
+// metricWithLabelValues provides the metric and its label values for
+// disambiguation on hash collision.
+type metricWithLabelValues struct {
+	values []string
+	metric Metric
 }
 }
 
 
 // Describe implements Collector. The length of the returned slice
 // Describe implements Collector. The length of the returned slice
@@ -42,8 +65,10 @@ func (m *MetricVec) Collect(ch chan<- Metric) {
 	m.mtx.RLock()
 	m.mtx.RLock()
 	defer m.mtx.RUnlock()
 	defer m.mtx.RUnlock()
 
 
-	for _, metric := range m.children {
-		ch <- metric
+	for _, metrics := range m.children {
+		for _, metric := range metrics {
+			ch <- metric.metric
+		}
 	}
 	}
 }
 }
 
 
@@ -77,16 +102,7 @@ func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	m.mtx.RLock()
-	metric, ok := m.children[h]
-	m.mtx.RUnlock()
-	if ok {
-		return metric, nil
-	}
-
-	m.mtx.Lock()
-	defer m.mtx.Unlock()
-	return m.getOrCreateMetric(h, lvs...), nil
+	return m.getOrCreateMetricWithLabelValues(h, lvs), nil
 }
 }
 
 
 // GetMetricWith returns the Metric for the given Labels map (the label names
 // GetMetricWith returns the Metric for the given Labels map (the label names
@@ -107,20 +123,7 @@ func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	m.mtx.RLock()
-	metric, ok := m.children[h]
-	m.mtx.RUnlock()
-	if ok {
-		return metric, nil
-	}
-
-	lvs := make([]string, len(labels))
-	for i, label := range m.desc.variableLabels {
-		lvs[i] = labels[label]
-	}
-	m.mtx.Lock()
-	defer m.mtx.Unlock()
-	return m.getOrCreateMetric(h, lvs...), nil
+	return m.getOrCreateMetricWithLabels(h, labels), nil
 }
 }
 
 
 // WithLabelValues works as GetMetricWithLabelValues, but panics if an error
 // WithLabelValues works as GetMetricWithLabelValues, but panics if an error
@@ -168,11 +171,7 @@ func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
 	if err != nil {
 	if err != nil {
 		return false
 		return false
 	}
 	}
-	if _, ok := m.children[h]; !ok {
-		return false
-	}
-	delete(m.children, h)
-	return true
+	return m.deleteByHashWithLabelValues(h, lvs)
 }
 }
 
 
 // Delete deletes the metric where the variable labels are the same as those
 // Delete deletes the metric where the variable labels are the same as those
@@ -193,10 +192,50 @@ func (m *MetricVec) Delete(labels Labels) bool {
 	if err != nil {
 	if err != nil {
 		return false
 		return false
 	}
 	}
-	if _, ok := m.children[h]; !ok {
+
+	return m.deleteByHashWithLabels(h, labels)
+}
+
+// deleteByHashWithLabelValues removes the metric from the hash bucket h. If
+// there are multiple matches in the bucket, use lvs to select a metric and
+// remove only that metric.
+func (m *MetricVec) deleteByHashWithLabelValues(h uint64, lvs []string) bool {
+	metrics, ok := m.children[h]
+	if !ok {
 		return false
 		return false
 	}
 	}
-	delete(m.children, h)
+
+	i := m.findMetricWithLabelValues(metrics, lvs)
+	if i >= len(metrics) {
+		return false
+	}
+
+	if len(metrics) > 1 {
+		m.children[h] = append(metrics[:i], metrics[i+1:]...)
+	} else {
+		delete(m.children, h)
+	}
+	return true
+}
+
+// deleteByHashWithLabels removes the metric from the hash bucket h. If there
+// are multiple matches in the bucket, use lvs to select a metric and remove
+// only that metric.
+func (m *MetricVec) deleteByHashWithLabels(h uint64, labels Labels) bool {
+	metrics, ok := m.children[h]
+	if !ok {
+		return false
+	}
+	i := m.findMetricWithLabels(metrics, labels)
+	if i >= len(metrics) {
+		return false
+	}
+
+	if len(metrics) > 1 {
+		m.children[h] = append(metrics[:i], metrics[i+1:]...)
+	} else {
+		delete(m.children, h)
+	}
 	return true
 	return true
 }
 }
 
 
@@ -216,7 +255,8 @@ func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
 	}
 	}
 	h := hashNew()
 	h := hashNew()
 	for _, val := range vals {
 	for _, val := range vals {
-		h = hashAdd(h, val)
+		h = m.hashAdd(h, val)
+		h = m.hashAddByte(h, model.SeparatorByte)
 	}
 	}
 	return h, nil
 	return h, nil
 }
 }
@@ -231,19 +271,134 @@ func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
 		if !ok {
 		if !ok {
 			return 0, fmt.Errorf("label name %q missing in label map", label)
 			return 0, fmt.Errorf("label name %q missing in label map", label)
 		}
 		}
-		h = hashAdd(h, val)
+		h = m.hashAdd(h, val)
+		h = m.hashAddByte(h, model.SeparatorByte)
 	}
 	}
 	return h, nil
 	return h, nil
 }
 }
 
 
-func (m *MetricVec) getOrCreateMetric(hash uint64, labelValues ...string) Metric {
-	metric, ok := m.children[hash]
+// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
+// or creates it and returns the new one.
+//
+// This function holds the mutex.
+func (m *MetricVec) getOrCreateMetricWithLabelValues(hash uint64, lvs []string) Metric {
+	m.mtx.RLock()
+	metric, ok := m.getMetricWithLabelValues(hash, lvs)
+	m.mtx.RUnlock()
+	if ok {
+		return metric
+	}
+
+	m.mtx.Lock()
+	defer m.mtx.Unlock()
+	metric, ok = m.getMetricWithLabelValues(hash, lvs)
+	if !ok {
+		// Copy to avoid allocation in case wo don't go down this code path.
+		copiedLVs := make([]string, len(lvs))
+		copy(copiedLVs, lvs)
+		metric = m.newMetric(copiedLVs...)
+		m.children[hash] = append(m.children[hash], metricWithLabelValues{values: copiedLVs, metric: metric})
+	}
+	return metric
+}
+
+// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
+// or creates it and returns the new one.
+//
+// This function holds the mutex.
+func (m *MetricVec) getOrCreateMetricWithLabels(hash uint64, labels Labels) Metric {
+	m.mtx.RLock()
+	metric, ok := m.getMetricWithLabels(hash, labels)
+	m.mtx.RUnlock()
+	if ok {
+		return metric
+	}
+
+	m.mtx.Lock()
+	defer m.mtx.Unlock()
+	metric, ok = m.getMetricWithLabels(hash, labels)
 	if !ok {
 	if !ok {
-		// Copy labelValues. Otherwise, they would be allocated even if we don't go
-		// down this code path.
-		copiedLabelValues := append(make([]string, 0, len(labelValues)), labelValues...)
-		metric = m.newMetric(copiedLabelValues...)
-		m.children[hash] = metric
+		lvs := m.extractLabelValues(labels)
+		metric = m.newMetric(lvs...)
+		m.children[hash] = append(m.children[hash], metricWithLabelValues{values: lvs, metric: metric})
 	}
 	}
 	return metric
 	return metric
 }
 }
+
+// getMetricWithLabelValues gets a metric while handling possible collisions in
+// the hash space. Must be called while holding read mutex.
+func (m *MetricVec) getMetricWithLabelValues(h uint64, lvs []string) (Metric, bool) {
+	metrics, ok := m.children[h]
+	if ok {
+		if i := m.findMetricWithLabelValues(metrics, lvs); i < len(metrics) {
+			return metrics[i].metric, true
+		}
+	}
+	return nil, false
+}
+
+// getMetricWithLabels gets a metric while handling possible collisions in
+// the hash space. Must be called while holding read mutex.
+func (m *MetricVec) getMetricWithLabels(h uint64, labels Labels) (Metric, bool) {
+	metrics, ok := m.children[h]
+	if ok {
+		if i := m.findMetricWithLabels(metrics, labels); i < len(metrics) {
+			return metrics[i].metric, true
+		}
+	}
+	return nil, false
+}
+
+// findMetricWithLabelValues returns the index of the matching metric or
+// len(metrics) if not found.
+func (m *MetricVec) findMetricWithLabelValues(metrics []metricWithLabelValues, lvs []string) int {
+	for i, metric := range metrics {
+		if m.matchLabelValues(metric.values, lvs) {
+			return i
+		}
+	}
+	return len(metrics)
+}
+
+// findMetricWithLabels returns the index of the matching metric or len(metrics)
+// if not found.
+func (m *MetricVec) findMetricWithLabels(metrics []metricWithLabelValues, labels Labels) int {
+	for i, metric := range metrics {
+		if m.matchLabels(metric.values, labels) {
+			return i
+		}
+	}
+	return len(metrics)
+}
+
+func (m *MetricVec) matchLabelValues(values []string, lvs []string) bool {
+	if len(values) != len(lvs) {
+		return false
+	}
+	for i, v := range values {
+		if v != lvs[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func (m *MetricVec) matchLabels(values []string, labels Labels) bool {
+	if len(labels) != len(values) {
+		return false
+	}
+	for i, k := range m.desc.variableLabels {
+		if values[i] != labels[k] {
+			return false
+		}
+	}
+	return true
+}
+
+func (m *MetricVec) extractLabelValues(labels Labels) []string {
+	labelValues := make([]string, len(labels))
+	for i, k := range m.desc.variableLabels {
+		labelValues[i] = labels[k]
+	}
+	return labelValues
+}

+ 2 - 2
vendor/github.com/prometheus/common/README.md

@@ -6,7 +6,7 @@ components and libraries.
 
 
 * **config**: Common configuration structures
 * **config**: Common configuration structures
 * **expfmt**: Decoding and encoding for the exposition format
 * **expfmt**: Decoding and encoding for the exposition format
-* **log**: A logging wrapper around [logrus](https://github.com/Sirupsen/logrus)
+* **log**: A logging wrapper around [logrus](https://github.com/sirupsen/logrus)
 * **model**: Shared data structures
 * **model**: Shared data structures
 * **route**: A routing wrapper around [httprouter](https://github.com/julienschmidt/httprouter) using `context.Context`
 * **route**: A routing wrapper around [httprouter](https://github.com/julienschmidt/httprouter) using `context.Context`
-* **version**: Version informations and metric
+* **version**: Version information and metrics

+ 32 - 15
vendor/github.com/prometheus/common/expfmt/decode.go

@@ -31,6 +31,7 @@ type Decoder interface {
 	Decode(*dto.MetricFamily) error
 	Decode(*dto.MetricFamily) error
 }
 }
 
 
+// DecodeOptions contains options used by the Decoder and in sample extraction.
 type DecodeOptions struct {
 type DecodeOptions struct {
 	// Timestamp is added to each value from the stream that has no explicit timestamp set.
 	// Timestamp is added to each value from the stream that has no explicit timestamp set.
 	Timestamp model.Time
 	Timestamp model.Time
@@ -142,6 +143,8 @@ func (d *textDecoder) Decode(v *dto.MetricFamily) error {
 	return nil
 	return nil
 }
 }
 
 
+// SampleDecoder wraps a Decoder to extract samples from the metric families
+// decoded by the wrapped Decoder.
 type SampleDecoder struct {
 type SampleDecoder struct {
 	Dec  Decoder
 	Dec  Decoder
 	Opts *DecodeOptions
 	Opts *DecodeOptions
@@ -149,37 +152,51 @@ type SampleDecoder struct {
 	f dto.MetricFamily
 	f dto.MetricFamily
 }
 }
 
 
+// Decode calls the Decode method of the wrapped Decoder and then extracts the
+// samples from the decoded MetricFamily into the provided model.Vector.
 func (sd *SampleDecoder) Decode(s *model.Vector) error {
 func (sd *SampleDecoder) Decode(s *model.Vector) error {
-	if err := sd.Dec.Decode(&sd.f); err != nil {
+	err := sd.Dec.Decode(&sd.f)
+	if err != nil {
 		return err
 		return err
 	}
 	}
-	*s = extractSamples(&sd.f, sd.Opts)
-	return nil
+	*s, err = extractSamples(&sd.f, sd.Opts)
+	return err
 }
 }
 
 
-// Extract samples builds a slice of samples from the provided metric families.
-func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) model.Vector {
-	var all model.Vector
+// ExtractSamples builds a slice of samples from the provided metric
+// families. If an error occurrs 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) {
+	var (
+		all     model.Vector
+		lastErr error
+	)
 	for _, f := range fams {
 	for _, f := range fams {
-		all = append(all, extractSamples(f, o)...)
+		some, err := extractSamples(f, o)
+		if err != nil {
+			lastErr = err
+			continue
+		}
+		all = append(all, some...)
 	}
 	}
-	return all
+	return all, lastErr
 }
 }
 
 
-func extractSamples(f *dto.MetricFamily, o *DecodeOptions) model.Vector {
+func extractSamples(f *dto.MetricFamily, o *DecodeOptions) (model.Vector, error) {
 	switch f.GetType() {
 	switch f.GetType() {
 	case dto.MetricType_COUNTER:
 	case dto.MetricType_COUNTER:
-		return extractCounter(o, f)
+		return extractCounter(o, f), nil
 	case dto.MetricType_GAUGE:
 	case dto.MetricType_GAUGE:
-		return extractGauge(o, f)
+		return extractGauge(o, f), nil
 	case dto.MetricType_SUMMARY:
 	case dto.MetricType_SUMMARY:
-		return extractSummary(o, f)
+		return extractSummary(o, f), nil
 	case dto.MetricType_UNTYPED:
 	case dto.MetricType_UNTYPED:
-		return extractUntyped(o, f)
+		return extractUntyped(o, f), nil
 	case dto.MetricType_HISTOGRAM:
 	case dto.MetricType_HISTOGRAM:
-		return extractHistogram(o, f)
+		return extractHistogram(o, f), nil
 	}
 	}
-	panic("expfmt.extractSamples: unknown metric family type")
+	return nil, fmt.Errorf("expfmt.extractSamples: unknown metric family type %v", f.GetType())
 }
 }
 
 
 func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
 func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector {

+ 5 - 7
vendor/github.com/prometheus/common/expfmt/expfmt.go

@@ -11,27 +11,25 @@
 // See the License for the specific language governing permissions and
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // limitations under the License.
 
 
-// A package for reading and writing Prometheus metrics.
+// Package expfmt contains tools for reading and writing Prometheus metrics.
 package expfmt
 package expfmt
 
 
+// Format specifies the HTTP content type of the different wire protocols.
 type Format string
 type Format string
 
 
+// Constants to assemble the Content-Type values for the different wire protocols.
 const (
 const (
-	TextVersion = "0.0.4"
-
+	TextVersion   = "0.0.4"
 	ProtoType     = `application/vnd.google.protobuf`
 	ProtoType     = `application/vnd.google.protobuf`
 	ProtoProtocol = `io.prometheus.client.MetricFamily`
 	ProtoProtocol = `io.prometheus.client.MetricFamily`
 	ProtoFmt      = ProtoType + "; proto=" + ProtoProtocol + ";"
 	ProtoFmt      = ProtoType + "; proto=" + ProtoProtocol + ";"
 
 
 	// The Content-Type values for the different wire protocols.
 	// The Content-Type values for the different wire protocols.
 	FmtUnknown      Format = `<unknown>`
 	FmtUnknown      Format = `<unknown>`
-	FmtText         Format = `text/plain; version=` + TextVersion
+	FmtText         Format = `text/plain; version=` + TextVersion + `; charset=utf-8`
 	FmtProtoDelim   Format = ProtoFmt + ` encoding=delimited`
 	FmtProtoDelim   Format = ProtoFmt + ` encoding=delimited`
 	FmtProtoText    Format = ProtoFmt + ` encoding=text`
 	FmtProtoText    Format = ProtoFmt + ` encoding=text`
 	FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
 	FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
-
-	// fmtJSON2 is hidden as it is deprecated.
-	fmtJSON2 Format = `application/json; version=0.0.2`
 )
 )
 
 
 const (
 const (

+ 5 - 2
vendor/github.com/prometheus/common/expfmt/text_create.go

@@ -25,9 +25,12 @@ import (
 
 
 // MetricFamilyToText converts a MetricFamily proto message into text format and
 // MetricFamilyToText converts a MetricFamily proto message into text format and
 // writes the resulting lines to 'out'. It returns the number of bytes written
 // writes the resulting lines to 'out'. It returns the number of bytes written
-// and any error encountered.  This function does not perform checks on the
-// content of the metric and label names, i.e. invalid metric or label names
+// 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.
 // will result in invalid text format output.
+//
 // This method fulfills the type 'prometheus.encoder'.
 // This method fulfills the type 'prometheus.encoder'.
 func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
 func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
 	var written int
 	var written int

+ 7 - 3
vendor/github.com/prometheus/common/expfmt/text_parse.go

@@ -47,7 +47,7 @@ func (e ParseError) Error() string {
 }
 }
 
 
 // TextParser is used to parse the simple and flat text-based exchange format. Its
 // TextParser is used to parse the simple and flat text-based exchange format. Its
-// nil value is ready to use.
+// zero value is ready to use.
 type TextParser struct {
 type TextParser struct {
 	metricFamiliesByName map[string]*dto.MetricFamily
 	metricFamiliesByName map[string]*dto.MetricFamily
 	buf                  *bufio.Reader // Where the parsed input is read through.
 	buf                  *bufio.Reader // Where the parsed input is read through.
@@ -315,6 +315,10 @@ func (p *TextParser) startLabelValue() stateFn {
 	if p.readTokenAsLabelValue(); p.err != nil {
 	if p.readTokenAsLabelValue(); p.err != nil {
 		return nil
 		return nil
 	}
 	}
+	if !model.LabelValue(p.currentToken.String()).IsValid() {
+		p.parseError(fmt.Sprintf("invalid label value %q", p.currentToken.String()))
+		return nil
+	}
 	p.currentLabelPair.Value = proto.String(p.currentToken.String())
 	p.currentLabelPair.Value = proto.String(p.currentToken.String())
 	// Special treatment of summaries:
 	// Special treatment of summaries:
 	// - Quantile labels are special, will result in dto.Quantile later.
 	// - Quantile labels are special, will result in dto.Quantile later.
@@ -552,8 +556,8 @@ func (p *TextParser) readTokenUntilWhitespace() {
 // byte considered is the byte already read (now in p.currentByte).  The first
 // byte considered is the byte already read (now in p.currentByte).  The first
 // newline byte encountered is still copied into p.currentByte, but not into
 // newline byte encountered is still copied into p.currentByte, but not into
 // p.currentToken. If recognizeEscapeSequence is true, two escape sequences are
 // p.currentToken. If recognizeEscapeSequence is true, two escape sequences are
-// recognized: '\\' tranlates into '\', and '\n' into a line-feed character. All
-// other escape sequences are invalid and cause an error.
+// recognized: '\\' translates into '\', and '\n' into a line-feed character.
+// All other escape sequences are invalid and cause an error.
 func (p *TextParser) readTokenUntilNewline(recognizeEscapeSequence bool) {
 func (p *TextParser) readTokenUntilNewline(recognizeEscapeSequence bool) {
 	p.currentToken.Reset()
 	p.currentToken.Reset()
 	escaped := false
 	escaped := false

+ 8 - 4
vendor/github.com/prometheus/common/model/labels.go

@@ -80,14 +80,18 @@ const (
 	QuantileLabel = "quantile"
 	QuantileLabel = "quantile"
 )
 )
 
 
-// LabelNameRE is a regular expression matching valid label names.
+// LabelNameRE is a regular expression matching valid label names. Note that the
+// IsValid method of LabelName performs the same check but faster than a match
+// with this regular expression.
 var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
 var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
 
 
 // A LabelName is a key for a LabelSet or Metric.  It has a value associated
 // A LabelName is a key for a LabelSet or Metric.  It has a value associated
 // therewith.
 // therewith.
 type LabelName string
 type LabelName string
 
 
-// IsValid is true iff the label name matches the pattern of LabelNameRE.
+// IsValid is true iff the label name matches the pattern of LabelNameRE. This
+// method, however, does not use LabelNameRE for the check but a much faster
+// hardcoded implementation.
 func (ln LabelName) IsValid() bool {
 func (ln LabelName) IsValid() bool {
 	if len(ln) == 0 {
 	if len(ln) == 0 {
 		return false
 		return false
@@ -106,7 +110,7 @@ func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	if err := unmarshal(&s); err != nil {
 	if err := unmarshal(&s); err != nil {
 		return err
 		return err
 	}
 	}
-	if !LabelNameRE.MatchString(s) {
+	if !LabelName(s).IsValid() {
 		return fmt.Errorf("%q is not a valid label name", s)
 		return fmt.Errorf("%q is not a valid label name", s)
 	}
 	}
 	*ln = LabelName(s)
 	*ln = LabelName(s)
@@ -119,7 +123,7 @@ func (ln *LabelName) UnmarshalJSON(b []byte) error {
 	if err := json.Unmarshal(b, &s); err != nil {
 	if err := json.Unmarshal(b, &s); err != nil {
 		return err
 		return err
 	}
 	}
-	if !LabelNameRE.MatchString(s) {
+	if !LabelName(s).IsValid() {
 		return fmt.Errorf("%q is not a valid label name", s)
 		return fmt.Errorf("%q is not a valid label name", s)
 	}
 	}
 	*ln = LabelName(s)
 	*ln = LabelName(s)

+ 1 - 1
vendor/github.com/prometheus/common/model/labelset.go

@@ -160,7 +160,7 @@ func (l *LabelSet) UnmarshalJSON(b []byte) error {
 	// LabelName as a string and does not call its UnmarshalJSON method.
 	// LabelName as a string and does not call its UnmarshalJSON method.
 	// Thus, we have to replicate the behavior here.
 	// Thus, we have to replicate the behavior here.
 	for ln := range m {
 	for ln := range m {
-		if !LabelNameRE.MatchString(string(ln)) {
+		if !ln.IsValid() {
 			return fmt.Errorf("%q is not a valid label name", ln)
 			return fmt.Errorf("%q is not a valid label name", ln)
 		}
 		}
 	}
 	}

+ 8 - 3
vendor/github.com/prometheus/common/model/metric.go

@@ -21,8 +21,11 @@ import (
 )
 )
 
 
 var (
 var (
-	separator    = []byte{0}
-	MetricNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`)
+	separator = []byte{0}
+	// MetricNameRE is a regular expression matching valid metric
+	// names. Note that the IsValidMetricName function performs the same
+	// check but faster than a match with this regular expression.
+	MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`)
 )
 )
 
 
 // A Metric is similar to a LabelSet, but the key difference is that a Metric is
 // A Metric is similar to a LabelSet, but the key difference is that a Metric is
@@ -41,7 +44,7 @@ func (m Metric) Before(o Metric) bool {
 
 
 // Clone returns a copy of the Metric.
 // Clone returns a copy of the Metric.
 func (m Metric) Clone() Metric {
 func (m Metric) Clone() Metric {
-	clone := Metric{}
+	clone := make(Metric, len(m))
 	for k, v := range m {
 	for k, v := range m {
 		clone[k] = v
 		clone[k] = v
 	}
 	}
@@ -85,6 +88,8 @@ func (m Metric) FastFingerprint() Fingerprint {
 }
 }
 
 
 // IsValidMetricName returns true iff name matches the pattern of MetricNameRE.
 // IsValidMetricName returns true iff name matches the pattern of MetricNameRE.
+// This function, however, does not use MetricNameRE for the check but a much
+// faster hardcoded implementation.
 func IsValidMetricName(n LabelValue) bool {
 func IsValidMetricName(n LabelValue) bool {
 	if len(n) == 0 {
 	if len(n) == 0 {
 		return false
 		return false

+ 2 - 2
vendor/github.com/prometheus/common/model/silence.go

@@ -59,8 +59,8 @@ func (m *Matcher) Validate() error {
 	return nil
 	return nil
 }
 }
 
 
-// Silence defines the representation of a silence definiton
-// in the Prometheus eco-system.
+// Silence defines the representation of a silence definition in the Prometheus
+// eco-system.
 type Silence struct {
 type Silence struct {
 	ID uint64 `json:"id,omitempty"`
 	ID uint64 `json:"id,omitempty"`
 
 

+ 16 - 1
vendor/github.com/prometheus/common/model/time.go

@@ -163,9 +163,21 @@ func (t *Time) UnmarshalJSON(b []byte) error {
 // This type should not propagate beyond the scope of input/output processing.
 // This type should not propagate beyond the scope of input/output processing.
 type Duration time.Duration
 type Duration time.Duration
 
 
+// Set implements pflag/flag.Value
+func (d *Duration) Set(s string) error {
+	var err error
+	*d, err = ParseDuration(s)
+	return err
+}
+
+// Type implements pflag.Value
+func (d *Duration) Type() string {
+	return "duration"
+}
+
 var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$")
 var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$")
 
 
-// StringToDuration parses a string into a time.Duration, assuming that a year
+// 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.
 // always has 365d, a week always has 7d, and a day always has 24h.
 func ParseDuration(durationStr string) (Duration, error) {
 func ParseDuration(durationStr string) (Duration, error) {
 	matches := durationRE.FindStringSubmatch(durationStr)
 	matches := durationRE.FindStringSubmatch(durationStr)
@@ -202,6 +214,9 @@ func (d Duration) String() string {
 		ms   = int64(time.Duration(d) / time.Millisecond)
 		ms   = int64(time.Duration(d) / time.Millisecond)
 		unit = "ms"
 		unit = "ms"
 	)
 	)
+	if ms == 0 {
+		return "0s"
+	}
 	factors := map[string]int64{
 	factors := map[string]int64{
 		"y":  1000 * 60 * 60 * 24 * 365,
 		"y":  1000 * 60 * 60 * 24 * 365,
 		"w":  1000 * 60 * 60 * 24 * 7,
 		"w":  1000 * 60 * 60 * 24 * 7,

+ 19 - 6
vendor/github.com/prometheus/common/model/value.go

@@ -22,6 +22,22 @@ import (
 	"strings"
 	"strings"
 )
 )
 
 
+var (
+	// ZeroSamplePair is the pseudo zero-value of SamplePair used to signal a
+	// non-existing sample pair. It is a SamplePair with timestamp Earliest and
+	// value 0.0. Note that the natural zero value of SamplePair has a timestamp
+	// of 0, which is possible to appear in a real SamplePair and thus not
+	// suitable to signal a non-existing SamplePair.
+	ZeroSamplePair = SamplePair{Timestamp: Earliest}
+
+	// ZeroSample is the pseudo zero-value of Sample used to signal a
+	// non-existing sample. It is a Sample with timestamp Earliest, value 0.0,
+	// and metric nil. Note that the natural zero value of Sample has a timestamp
+	// of 0, which is possible to appear in a real Sample and thus not suitable
+	// to signal a non-existing Sample.
+	ZeroSample = Sample{Timestamp: Earliest}
+)
+
 // A SampleValue is a representation of a value for a given sample at a given
 // A SampleValue is a representation of a value for a given sample at a given
 // time.
 // time.
 type SampleValue float64
 type SampleValue float64
@@ -84,7 +100,7 @@ func (s *SamplePair) UnmarshalJSON(b []byte) error {
 }
 }
 
 
 // Equal returns true if this SamplePair and o have equal Values and equal
 // Equal returns true if this SamplePair and o have equal Values and equal
-// Timestamps. The sematics of Value equality is defined by SampleValue.Equal.
+// Timestamps. The semantics of Value equality is defined by SampleValue.Equal.
 func (s *SamplePair) Equal(o *SamplePair) bool {
 func (s *SamplePair) Equal(o *SamplePair) bool {
 	return s == o || (s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp))
 	return s == o || (s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp))
 }
 }
@@ -101,7 +117,7 @@ type Sample struct {
 }
 }
 
 
 // Equal compares first the metrics, then the timestamp, then the value. The
 // Equal compares first the metrics, then the timestamp, then the value. The
-// sematics of value equality is defined by SampleValue.Equal.
+// semantics of value equality is defined by SampleValue.Equal.
 func (s *Sample) Equal(o *Sample) bool {
 func (s *Sample) Equal(o *Sample) bool {
 	if s == o {
 	if s == o {
 		return true
 		return true
@@ -113,11 +129,8 @@ func (s *Sample) Equal(o *Sample) bool {
 	if !s.Timestamp.Equal(o.Timestamp) {
 	if !s.Timestamp.Equal(o.Timestamp) {
 		return false
 		return false
 	}
 	}
-	if s.Value.Equal(o.Value) {
-		return false
-	}
 
 
-	return true
+	return s.Value.Equal(o.Value)
 }
 }
 
 
 func (s Sample) String() string {
 func (s Sample) String() string {

+ 1 - 0
vendor/github.com/prometheus/procfs/README.md

@@ -8,3 +8,4 @@ backwards-incompatible ways without warnings. Use it at your own risk.
 
 
 [![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs)
 [![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs)
 [![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs)
 [![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs)
+[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs)

+ 95 - 0
vendor/github.com/prometheus/procfs/buddyinfo.go

@@ -0,0 +1,95 @@
+// Copyright 2017 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 procfs
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"os"
+	"strconv"
+	"strings"
+)
+
+// A BuddyInfo is the details parsed from /proc/buddyinfo.
+// The data is comprised of an array of free fragments of each size.
+// The sizes are 2^n*PAGE_SIZE, where n is the array index.
+type BuddyInfo struct {
+	Node  string
+	Zone  string
+	Sizes []float64
+}
+
+// NewBuddyInfo reads the buddyinfo statistics.
+func NewBuddyInfo() ([]BuddyInfo, error) {
+	fs, err := NewFS(DefaultMountPoint)
+	if err != nil {
+		return nil, err
+	}
+
+	return fs.NewBuddyInfo()
+}
+
+// NewBuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem.
+func (fs FS) NewBuddyInfo() ([]BuddyInfo, error) {
+	file, err := os.Open(fs.Path("buddyinfo"))
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+
+	return parseBuddyInfo(file)
+}
+
+func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
+	var (
+		buddyInfo   = []BuddyInfo{}
+		scanner     = bufio.NewScanner(r)
+		bucketCount = -1
+	)
+
+	for scanner.Scan() {
+		var err error
+		line := scanner.Text()
+		parts := strings.Fields(line)
+
+		if len(parts) < 4 {
+			return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo")
+		}
+
+		node := strings.TrimRight(parts[1], ",")
+		zone := strings.TrimRight(parts[3], ",")
+		arraySize := len(parts[4:])
+
+		if bucketCount == -1 {
+			bucketCount = arraySize
+		} else {
+			if bucketCount != arraySize {
+				return nil, fmt.Errorf("mismatch in number of buddyinfo buckets, previous count %d, new count %d", bucketCount, arraySize)
+			}
+		}
+
+		sizes := make([]float64, arraySize)
+		for i := 0; i < arraySize; i++ {
+			sizes[i], err = strconv.ParseFloat(parts[i+4], 64)
+			if err != nil {
+				return nil, fmt.Errorf("invalid value in buddyinfo: %s", err)
+			}
+		}
+
+		buddyInfo = append(buddyInfo, BuddyInfo{node, zone, sizes})
+	}
+
+	return buddyInfo, scanner.Err()
+}

+ 49 - 0
vendor/github.com/prometheus/procfs/fs.go

@@ -1,9 +1,25 @@
+// Copyright 2018 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 procfs
 package procfs
 
 
 import (
 import (
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 	"path"
 	"path"
+
+	"github.com/prometheus/procfs/nfs"
+	"github.com/prometheus/procfs/xfs"
 )
 )
 
 
 // FS represents the pseudo-filesystem proc, which provides an interface to
 // FS represents the pseudo-filesystem proc, which provides an interface to
@@ -31,3 +47,36 @@ func NewFS(mountPoint string) (FS, error) {
 func (fs FS) Path(p ...string) string {
 func (fs FS) Path(p ...string) string {
 	return path.Join(append([]string{string(fs)}, p...)...)
 	return path.Join(append([]string{string(fs)}, p...)...)
 }
 }
+
+// XFSStats retrieves XFS filesystem runtime statistics.
+func (fs FS) XFSStats() (*xfs.Stats, error) {
+	f, err := os.Open(fs.Path("fs/xfs/stat"))
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	return xfs.ParseStats(f)
+}
+
+// NFSClientRPCStats retrieves NFS client RPC statistics.
+func (fs FS) NFSClientRPCStats() (*nfs.ClientRPCStats, error) {
+	f, err := os.Open(fs.Path("net/rpc/nfs"))
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	return nfs.ParseClientRPCStats(f)
+}
+
+// NFSdServerRPCStats retrieves NFS daemon RPC statistics.
+func (fs FS) NFSdServerRPCStats() (*nfs.ServerRPCStats, error) {
+	f, err := os.Open(fs.Path("net/rpc/nfsd"))
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	return nfs.ParseServerRPCStats(f)
+}

+ 46 - 0
vendor/github.com/prometheus/procfs/internal/util/parse.go

@@ -0,0 +1,46 @@
+// Copyright 2018 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 util
+
+import "strconv"
+
+// ParseUint32s parses a slice of strings into a slice of uint32s.
+func ParseUint32s(ss []string) ([]uint32, error) {
+	us := make([]uint32, 0, len(ss))
+	for _, s := range ss {
+		u, err := strconv.ParseUint(s, 10, 32)
+		if err != nil {
+			return nil, err
+		}
+
+		us = append(us, uint32(u))
+	}
+
+	return us, nil
+}
+
+// ParseUint64s parses a slice of strings into a slice of uint64s.
+func ParseUint64s(ss []string) ([]uint64, error) {
+	us := make([]uint64, 0, len(ss))
+	for _, s := range ss {
+		u, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, err
+		}
+
+		us = append(us, u)
+	}
+
+	return us, nil
+}

+ 52 - 17
vendor/github.com/prometheus/procfs/ipvs.go

@@ -1,3 +1,16 @@
+// Copyright 2018 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 procfs
 package procfs
 
 
 import (
 import (
@@ -31,14 +44,16 @@ type IPVSStats struct {
 type IPVSBackendStatus struct {
 type IPVSBackendStatus struct {
 	// The local (virtual) IP address.
 	// The local (virtual) IP address.
 	LocalAddress net.IP
 	LocalAddress net.IP
-	// The local (virtual) port.
-	LocalPort uint16
-	// The transport protocol (TCP, UDP).
-	Proto string
 	// The remote (real) IP address.
 	// The remote (real) IP address.
 	RemoteAddress net.IP
 	RemoteAddress net.IP
+	// The local (virtual) port.
+	LocalPort uint16
 	// The remote (real) port.
 	// The remote (real) port.
 	RemotePort uint16
 	RemotePort uint16
+	// The local firewall mark
+	LocalMark string
+	// The transport protocol (TCP, UDP).
+	Proto string
 	// The current number of active connections for this virtual/real address pair.
 	// The current number of active connections for this virtual/real address pair.
 	ActiveConn uint64
 	ActiveConn uint64
 	// The current number of inactive connections for this virtual/real address pair.
 	// The current number of inactive connections for this virtual/real address pair.
@@ -142,13 +157,14 @@ func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) {
 		status       []IPVSBackendStatus
 		status       []IPVSBackendStatus
 		scanner      = bufio.NewScanner(file)
 		scanner      = bufio.NewScanner(file)
 		proto        string
 		proto        string
+		localMark    string
 		localAddress net.IP
 		localAddress net.IP
 		localPort    uint16
 		localPort    uint16
 		err          error
 		err          error
 	)
 	)
 
 
 	for scanner.Scan() {
 	for scanner.Scan() {
-		fields := strings.Fields(string(scanner.Text()))
+		fields := strings.Fields(scanner.Text())
 		if len(fields) == 0 {
 		if len(fields) == 0 {
 			continue
 			continue
 		}
 		}
@@ -160,10 +176,19 @@ func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) {
 				continue
 				continue
 			}
 			}
 			proto = fields[0]
 			proto = fields[0]
+			localMark = ""
 			localAddress, localPort, err = parseIPPort(fields[1])
 			localAddress, localPort, err = parseIPPort(fields[1])
 			if err != nil {
 			if err != nil {
 				return nil, err
 				return nil, err
 			}
 			}
+		case fields[0] == "FWM":
+			if len(fields) < 2 {
+				continue
+			}
+			proto = fields[0]
+			localMark = fields[1]
+			localAddress = nil
+			localPort = 0
 		case fields[0] == "->":
 		case fields[0] == "->":
 			if len(fields) < 6 {
 			if len(fields) < 6 {
 				continue
 				continue
@@ -187,6 +212,7 @@ func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) {
 			status = append(status, IPVSBackendStatus{
 			status = append(status, IPVSBackendStatus{
 				LocalAddress:  localAddress,
 				LocalAddress:  localAddress,
 				LocalPort:     localPort,
 				LocalPort:     localPort,
+				LocalMark:     localMark,
 				RemoteAddress: remoteAddress,
 				RemoteAddress: remoteAddress,
 				RemotePort:    remotePort,
 				RemotePort:    remotePort,
 				Proto:         proto,
 				Proto:         proto,
@@ -200,22 +226,31 @@ func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) {
 }
 }
 
 
 func parseIPPort(s string) (net.IP, uint16, error) {
 func parseIPPort(s string) (net.IP, uint16, error) {
-	tmp := strings.SplitN(s, ":", 2)
-
-	if len(tmp) != 2 {
-		return nil, 0, fmt.Errorf("invalid IP:Port: %s", s)
-	}
+	var (
+		ip  net.IP
+		err error
+	)
 
 
-	if len(tmp[0]) != 8 && len(tmp[0]) != 32 {
-		return nil, 0, fmt.Errorf("invalid IP: %s", tmp[0])
+	switch len(s) {
+	case 13:
+		ip, err = hex.DecodeString(s[0:8])
+		if err != nil {
+			return nil, 0, err
+		}
+	case 46:
+		ip = net.ParseIP(s[1:40])
+		if ip == nil {
+			return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40])
+		}
+	default:
+		return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s)
 	}
 	}
 
 
-	ip, err := hex.DecodeString(tmp[0])
-	if err != nil {
-		return nil, 0, err
+	portString := s[len(s)-4:]
+	if len(portString) != 4 {
+		return nil, 0, fmt.Errorf("unexpected port string format: %s", portString)
 	}
 	}
-
-	port, err := strconv.ParseUint(tmp[1], 16, 16)
+	port, err := strconv.ParseUint(portString, 16, 16)
 	if err != nil {
 	if err != nil {
 		return nil, 0, err
 		return nil, 0, err
 	}
 	}

+ 13 - 0
vendor/github.com/prometheus/procfs/mdstat.go

@@ -1,3 +1,16 @@
+// Copyright 2018 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 procfs
 package procfs
 
 
 import (
 import (

+ 569 - 0
vendor/github.com/prometheus/procfs/mountstats.go

@@ -0,0 +1,569 @@
+// Copyright 2018 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 procfs
+
+// While implementing parsing of /proc/[pid]/mountstats, this blog was used
+// heavily as a reference:
+//   https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex
+//
+// Special thanks to Chris Siebenmann for all of his posts explaining the
+// various statistics available for NFS.
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// Constants shared between multiple functions.
+const (
+	deviceEntryLen = 8
+
+	fieldBytesLen  = 8
+	fieldEventsLen = 27
+
+	statVersion10 = "1.0"
+	statVersion11 = "1.1"
+
+	fieldTransport10Len = 10
+	fieldTransport11Len = 13
+)
+
+// A Mount is a device mount parsed from /proc/[pid]/mountstats.
+type Mount struct {
+	// Name of the device.
+	Device string
+	// The mount point of the device.
+	Mount string
+	// The filesystem type used by the device.
+	Type string
+	// If available additional statistics related to this Mount.
+	// Use a type assertion to determine if additional statistics are available.
+	Stats MountStats
+}
+
+// A MountStats is a type which contains detailed statistics for a specific
+// type of Mount.
+type MountStats interface {
+	mountStats()
+}
+
+// A MountStatsNFS is a MountStats implementation for NFSv3 and v4 mounts.
+type MountStatsNFS struct {
+	// The version of statistics provided.
+	StatVersion string
+	// The age of the NFS mount.
+	Age time.Duration
+	// Statistics related to byte counters for various operations.
+	Bytes NFSBytesStats
+	// Statistics related to various NFS event occurrences.
+	Events NFSEventsStats
+	// Statistics broken down by filesystem operation.
+	Operations []NFSOperationStats
+	// Statistics about the NFS RPC transport.
+	Transport NFSTransportStats
+}
+
+// mountStats implements MountStats.
+func (m MountStatsNFS) mountStats() {}
+
+// A NFSBytesStats contains statistics about the number of bytes read and written
+// by an NFS client to and from an NFS server.
+type NFSBytesStats struct {
+	// Number of bytes read using the read() syscall.
+	Read uint64
+	// Number of bytes written using the write() syscall.
+	Write uint64
+	// Number of bytes read using the read() syscall in O_DIRECT mode.
+	DirectRead uint64
+	// Number of bytes written using the write() syscall in O_DIRECT mode.
+	DirectWrite uint64
+	// Number of bytes read from the NFS server, in total.
+	ReadTotal uint64
+	// Number of bytes written to the NFS server, in total.
+	WriteTotal uint64
+	// Number of pages read directly via mmap()'d files.
+	ReadPages uint64
+	// Number of pages written directly via mmap()'d files.
+	WritePages uint64
+}
+
+// A NFSEventsStats contains statistics about NFS event occurrences.
+type NFSEventsStats struct {
+	// Number of times cached inode attributes are re-validated from the server.
+	InodeRevalidate uint64
+	// Number of times cached dentry nodes are re-validated from the server.
+	DnodeRevalidate uint64
+	// Number of times an inode cache is cleared.
+	DataInvalidate uint64
+	// Number of times cached inode attributes are invalidated.
+	AttributeInvalidate uint64
+	// Number of times files or directories have been open()'d.
+	VFSOpen uint64
+	// Number of times a directory lookup has occurred.
+	VFSLookup uint64
+	// Number of times permissions have been checked.
+	VFSAccess uint64
+	// Number of updates (and potential writes) to pages.
+	VFSUpdatePage uint64
+	// Number of pages read directly via mmap()'d files.
+	VFSReadPage uint64
+	// Number of times a group of pages have been read.
+	VFSReadPages uint64
+	// Number of pages written directly via mmap()'d files.
+	VFSWritePage uint64
+	// Number of times a group of pages have been written.
+	VFSWritePages uint64
+	// Number of times directory entries have been read with getdents().
+	VFSGetdents uint64
+	// Number of times attributes have been set on inodes.
+	VFSSetattr uint64
+	// Number of pending writes that have been forcefully flushed to the server.
+	VFSFlush uint64
+	// Number of times fsync() has been called on directories and files.
+	VFSFsync uint64
+	// Number of times locking has been attempted on a file.
+	VFSLock uint64
+	// Number of times files have been closed and released.
+	VFSFileRelease uint64
+	// Unknown.  Possibly unused.
+	CongestionWait uint64
+	// Number of times files have been truncated.
+	Truncation uint64
+	// Number of times a file has been grown due to writes beyond its existing end.
+	WriteExtension uint64
+	// Number of times a file was removed while still open by another process.
+	SillyRename uint64
+	// Number of times the NFS server gave less data than expected while reading.
+	ShortRead uint64
+	// Number of times the NFS server wrote less data than expected while writing.
+	ShortWrite uint64
+	// Number of times the NFS server indicated EJUKEBOX; retrieving data from
+	// offline storage.
+	JukeboxDelay uint64
+	// Number of NFS v4.1+ pNFS reads.
+	PNFSRead uint64
+	// Number of NFS v4.1+ pNFS writes.
+	PNFSWrite uint64
+}
+
+// A NFSOperationStats contains statistics for a single operation.
+type NFSOperationStats struct {
+	// The name of the operation.
+	Operation string
+	// Number of requests performed for this operation.
+	Requests uint64
+	// Number of times an actual RPC request has been transmitted for this operation.
+	Transmissions uint64
+	// Number of times a request has had a major timeout.
+	MajorTimeouts uint64
+	// Number of bytes sent for this operation, including RPC headers and payload.
+	BytesSent uint64
+	// Number of bytes received for this operation, including RPC headers and payload.
+	BytesReceived uint64
+	// Duration all requests spent queued for transmission before they were sent.
+	CumulativeQueueTime time.Duration
+	// Duration it took to get a reply back after the request was transmitted.
+	CumulativeTotalResponseTime time.Duration
+	// Duration from when a request was enqueued to when it was completely handled.
+	CumulativeTotalRequestTime time.Duration
+}
+
+// A NFSTransportStats contains statistics for the NFS mount RPC requests and
+// responses.
+type NFSTransportStats struct {
+	// The local port used for the NFS mount.
+	Port uint64
+	// Number of times the client has had to establish a connection from scratch
+	// to the NFS server.
+	Bind uint64
+	// Number of times the client has made a TCP connection to the NFS server.
+	Connect uint64
+	// Duration (in jiffies, a kernel internal unit of time) the NFS mount has
+	// spent waiting for connections to the server to be established.
+	ConnectIdleTime uint64
+	// Duration since the NFS mount last saw any RPC traffic.
+	IdleTime time.Duration
+	// Number of RPC requests for this mount sent to the NFS server.
+	Sends uint64
+	// Number of RPC responses for this mount received from the NFS server.
+	Receives uint64
+	// Number of times the NFS server sent a response with a transaction ID
+	// unknown to this client.
+	BadTransactionIDs uint64
+	// A running counter, incremented on each request as the current difference
+	// ebetween sends and receives.
+	CumulativeActiveRequests uint64
+	// A running counter, incremented on each request by the current backlog
+	// queue size.
+	CumulativeBacklog uint64
+
+	// Stats below only available with stat version 1.1.
+
+	// Maximum number of simultaneously active RPC requests ever used.
+	MaximumRPCSlotsUsed uint64
+	// A running counter, incremented on each request as the current size of the
+	// sending queue.
+	CumulativeSendingQueue uint64
+	// A running counter, incremented on each request as the current size of the
+	// pending queue.
+	CumulativePendingQueue uint64
+}
+
+// parseMountStats parses a /proc/[pid]/mountstats file and returns a slice
+// of Mount structures containing detailed information about each mount.
+// If available, statistics for each mount are parsed as well.
+func parseMountStats(r io.Reader) ([]*Mount, error) {
+	const (
+		device            = "device"
+		statVersionPrefix = "statvers="
+
+		nfs3Type = "nfs"
+		nfs4Type = "nfs4"
+	)
+
+	var mounts []*Mount
+
+	s := bufio.NewScanner(r)
+	for s.Scan() {
+		// Only look for device entries in this function
+		ss := strings.Fields(string(s.Bytes()))
+		if len(ss) == 0 || ss[0] != device {
+			continue
+		}
+
+		m, err := parseMount(ss)
+		if err != nil {
+			return nil, err
+		}
+
+		// Does this mount also possess statistics information?
+		if len(ss) > deviceEntryLen {
+			// Only NFSv3 and v4 are supported for parsing statistics
+			if m.Type != nfs3Type && m.Type != nfs4Type {
+				return nil, fmt.Errorf("cannot parse MountStats for fstype %q", m.Type)
+			}
+
+			statVersion := strings.TrimPrefix(ss[8], statVersionPrefix)
+
+			stats, err := parseMountStatsNFS(s, statVersion)
+			if err != nil {
+				return nil, err
+			}
+
+			m.Stats = stats
+		}
+
+		mounts = append(mounts, m)
+	}
+
+	return mounts, s.Err()
+}
+
+// parseMount parses an entry in /proc/[pid]/mountstats in the format:
+//   device [device] mounted on [mount] with fstype [type]
+func parseMount(ss []string) (*Mount, error) {
+	if len(ss) < deviceEntryLen {
+		return nil, fmt.Errorf("invalid device entry: %v", ss)
+	}
+
+	// Check for specific words appearing at specific indices to ensure
+	// the format is consistent with what we expect
+	format := []struct {
+		i int
+		s string
+	}{
+		{i: 0, s: "device"},
+		{i: 2, s: "mounted"},
+		{i: 3, s: "on"},
+		{i: 5, s: "with"},
+		{i: 6, s: "fstype"},
+	}
+
+	for _, f := range format {
+		if ss[f.i] != f.s {
+			return nil, fmt.Errorf("invalid device entry: %v", ss)
+		}
+	}
+
+	return &Mount{
+		Device: ss[1],
+		Mount:  ss[4],
+		Type:   ss[7],
+	}, nil
+}
+
+// parseMountStatsNFS parses a MountStatsNFS by scanning additional information
+// related to NFS statistics.
+func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) {
+	// Field indicators for parsing specific types of data
+	const (
+		fieldAge        = "age:"
+		fieldBytes      = "bytes:"
+		fieldEvents     = "events:"
+		fieldPerOpStats = "per-op"
+		fieldTransport  = "xprt:"
+	)
+
+	stats := &MountStatsNFS{
+		StatVersion: statVersion,
+	}
+
+	for s.Scan() {
+		ss := strings.Fields(string(s.Bytes()))
+		if len(ss) == 0 {
+			break
+		}
+		if len(ss) < 2 {
+			return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
+		}
+
+		switch ss[0] {
+		case fieldAge:
+			// Age integer is in seconds
+			d, err := time.ParseDuration(ss[1] + "s")
+			if err != nil {
+				return nil, err
+			}
+
+			stats.Age = d
+		case fieldBytes:
+			bstats, err := parseNFSBytesStats(ss[1:])
+			if err != nil {
+				return nil, err
+			}
+
+			stats.Bytes = *bstats
+		case fieldEvents:
+			estats, err := parseNFSEventsStats(ss[1:])
+			if err != nil {
+				return nil, err
+			}
+
+			stats.Events = *estats
+		case fieldTransport:
+			if len(ss) < 3 {
+				return nil, fmt.Errorf("not enough information for NFS transport stats: %v", ss)
+			}
+
+			tstats, err := parseNFSTransportStats(ss[2:], statVersion)
+			if err != nil {
+				return nil, err
+			}
+
+			stats.Transport = *tstats
+		}
+
+		// When encountering "per-operation statistics", we must break this
+		// loop and parse them separately to ensure we can terminate parsing
+		// before reaching another device entry; hence why this 'if' statement
+		// is not just another switch case
+		if ss[0] == fieldPerOpStats {
+			break
+		}
+	}
+
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+
+	// NFS per-operation stats appear last before the next device entry
+	perOpStats, err := parseNFSOperationStats(s)
+	if err != nil {
+		return nil, err
+	}
+
+	stats.Operations = perOpStats
+
+	return stats, nil
+}
+
+// parseNFSBytesStats parses a NFSBytesStats line using an input set of
+// integer fields.
+func parseNFSBytesStats(ss []string) (*NFSBytesStats, error) {
+	if len(ss) != fieldBytesLen {
+		return nil, fmt.Errorf("invalid NFS bytes stats: %v", ss)
+	}
+
+	ns := make([]uint64, 0, fieldBytesLen)
+	for _, s := range ss {
+		n, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, err
+		}
+
+		ns = append(ns, n)
+	}
+
+	return &NFSBytesStats{
+		Read:        ns[0],
+		Write:       ns[1],
+		DirectRead:  ns[2],
+		DirectWrite: ns[3],
+		ReadTotal:   ns[4],
+		WriteTotal:  ns[5],
+		ReadPages:   ns[6],
+		WritePages:  ns[7],
+	}, nil
+}
+
+// parseNFSEventsStats parses a NFSEventsStats line using an input set of
+// integer fields.
+func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) {
+	if len(ss) != fieldEventsLen {
+		return nil, fmt.Errorf("invalid NFS events stats: %v", ss)
+	}
+
+	ns := make([]uint64, 0, fieldEventsLen)
+	for _, s := range ss {
+		n, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, err
+		}
+
+		ns = append(ns, n)
+	}
+
+	return &NFSEventsStats{
+		InodeRevalidate:     ns[0],
+		DnodeRevalidate:     ns[1],
+		DataInvalidate:      ns[2],
+		AttributeInvalidate: ns[3],
+		VFSOpen:             ns[4],
+		VFSLookup:           ns[5],
+		VFSAccess:           ns[6],
+		VFSUpdatePage:       ns[7],
+		VFSReadPage:         ns[8],
+		VFSReadPages:        ns[9],
+		VFSWritePage:        ns[10],
+		VFSWritePages:       ns[11],
+		VFSGetdents:         ns[12],
+		VFSSetattr:          ns[13],
+		VFSFlush:            ns[14],
+		VFSFsync:            ns[15],
+		VFSLock:             ns[16],
+		VFSFileRelease:      ns[17],
+		CongestionWait:      ns[18],
+		Truncation:          ns[19],
+		WriteExtension:      ns[20],
+		SillyRename:         ns[21],
+		ShortRead:           ns[22],
+		ShortWrite:          ns[23],
+		JukeboxDelay:        ns[24],
+		PNFSRead:            ns[25],
+		PNFSWrite:           ns[26],
+	}, nil
+}
+
+// parseNFSOperationStats parses a slice of NFSOperationStats by scanning
+// additional information about per-operation statistics until an empty
+// line is reached.
+func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
+	const (
+		// Number of expected fields in each per-operation statistics set
+		numFields = 9
+	)
+
+	var ops []NFSOperationStats
+
+	for s.Scan() {
+		ss := strings.Fields(string(s.Bytes()))
+		if len(ss) == 0 {
+			// Must break when reading a blank line after per-operation stats to
+			// enable top-level function to parse the next device entry
+			break
+		}
+
+		if len(ss) != numFields {
+			return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss)
+		}
+
+		// Skip string operation name for integers
+		ns := make([]uint64, 0, numFields-1)
+		for _, st := range ss[1:] {
+			n, err := strconv.ParseUint(st, 10, 64)
+			if err != nil {
+				return nil, err
+			}
+
+			ns = append(ns, n)
+		}
+
+		ops = append(ops, NFSOperationStats{
+			Operation:                   strings.TrimSuffix(ss[0], ":"),
+			Requests:                    ns[0],
+			Transmissions:               ns[1],
+			MajorTimeouts:               ns[2],
+			BytesSent:                   ns[3],
+			BytesReceived:               ns[4],
+			CumulativeQueueTime:         time.Duration(ns[5]) * time.Millisecond,
+			CumulativeTotalResponseTime: time.Duration(ns[6]) * time.Millisecond,
+			CumulativeTotalRequestTime:  time.Duration(ns[7]) * time.Millisecond,
+		})
+	}
+
+	return ops, s.Err()
+}
+
+// parseNFSTransportStats parses a NFSTransportStats line using an input set of
+// integer fields matched to a specific stats version.
+func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats, error) {
+	switch statVersion {
+	case statVersion10:
+		if len(ss) != fieldTransport10Len {
+			return nil, fmt.Errorf("invalid NFS transport stats 1.0 statement: %v", ss)
+		}
+	case statVersion11:
+		if len(ss) != fieldTransport11Len {
+			return nil, fmt.Errorf("invalid NFS transport stats 1.1 statement: %v", ss)
+		}
+	default:
+		return nil, fmt.Errorf("unrecognized NFS transport stats version: %q", statVersion)
+	}
+
+	// Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay
+	// in a v1.0 response.
+	//
+	// Note: slice length must be set to length of v1.1 stats to avoid a panic when
+	// only v1.0 stats are present.
+	// See: https://github.com/prometheus/node_exporter/issues/571.
+	ns := make([]uint64, fieldTransport11Len)
+	for i, s := range ss {
+		n, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return nil, err
+		}
+
+		ns[i] = n
+	}
+
+	return &NFSTransportStats{
+		Port:                     ns[0],
+		Bind:                     ns[1],
+		Connect:                  ns[2],
+		ConnectIdleTime:          ns[3],
+		IdleTime:                 time.Duration(ns[4]) * time.Second,
+		Sends:                    ns[5],
+		Receives:                 ns[6],
+		BadTransactionIDs:        ns[7],
+		CumulativeActiveRequests: ns[8],
+		CumulativeBacklog:        ns[9],
+		MaximumRPCSlotsUsed:      ns[10],
+		CumulativeSendingQueue:   ns[11],
+		CumulativePendingQueue:   ns[12],
+	}, nil
+}

+ 216 - 0
vendor/github.com/prometheus/procfs/net_dev.go

@@ -0,0 +1,216 @@
+// Copyright 2018 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 procfs
+
+import (
+	"bufio"
+	"errors"
+	"os"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+// NetDevLine is single line parsed from /proc/net/dev or /proc/[pid]/net/dev.
+type NetDevLine struct {
+	Name         string `json:"name"`          // The name of the interface.
+	RxBytes      uint64 `json:"rx_bytes"`      // Cumulative count of bytes received.
+	RxPackets    uint64 `json:"rx_packets"`    // Cumulative count of packets received.
+	RxErrors     uint64 `json:"rx_errors"`     // Cumulative count of receive errors encountered.
+	RxDropped    uint64 `json:"rx_dropped"`    // Cumulative count of packets dropped while receiving.
+	RxFIFO       uint64 `json:"rx_fifo"`       // Cumulative count of FIFO buffer errors.
+	RxFrame      uint64 `json:"rx_frame"`      // Cumulative count of packet framing errors.
+	RxCompressed uint64 `json:"rx_compressed"` // Cumulative count of compressed packets received by the device driver.
+	RxMulticast  uint64 `json:"rx_multicast"`  // Cumulative count of multicast frames received by the device driver.
+	TxBytes      uint64 `json:"tx_bytes"`      // Cumulative count of bytes transmitted.
+	TxPackets    uint64 `json:"tx_packets"`    // Cumulative count of packets transmitted.
+	TxErrors     uint64 `json:"tx_errors"`     // Cumulative count of transmit errors encountered.
+	TxDropped    uint64 `json:"tx_dropped"`    // Cumulative count of packets dropped while transmitting.
+	TxFIFO       uint64 `json:"tx_fifo"`       // Cumulative count of FIFO buffer errors.
+	TxCollisions uint64 `json:"tx_collisions"` // Cumulative count of collisions detected on the interface.
+	TxCarrier    uint64 `json:"tx_carrier"`    // Cumulative count of carrier losses detected by the device driver.
+	TxCompressed uint64 `json:"tx_compressed"` // Cumulative count of compressed packets transmitted by the device driver.
+}
+
+// NetDev is parsed from /proc/net/dev or /proc/[pid]/net/dev. The map keys
+// are interface names.
+type NetDev map[string]NetDevLine
+
+// NewNetDev returns kernel/system statistics read from /proc/net/dev.
+func NewNetDev() (NetDev, error) {
+	fs, err := NewFS(DefaultMountPoint)
+	if err != nil {
+		return nil, err
+	}
+
+	return fs.NewNetDev()
+}
+
+// NewNetDev returns kernel/system statistics read from /proc/net/dev.
+func (fs FS) NewNetDev() (NetDev, error) {
+	return newNetDev(fs.Path("net/dev"))
+}
+
+// NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev.
+func (p Proc) NewNetDev() (NetDev, error) {
+	return newNetDev(p.path("net/dev"))
+}
+
+// newNetDev creates a new NetDev from the contents of the given file.
+func newNetDev(file string) (NetDev, error) {
+	f, err := os.Open(file)
+	if err != nil {
+		return NetDev{}, err
+	}
+	defer f.Close()
+
+	nd := NetDev{}
+	s := bufio.NewScanner(f)
+	for n := 0; s.Scan(); n++ {
+		// Skip the 2 header lines.
+		if n < 2 {
+			continue
+		}
+
+		line, err := nd.parseLine(s.Text())
+		if err != nil {
+			return nd, err
+		}
+
+		nd[line.Name] = *line
+	}
+
+	return nd, s.Err()
+}
+
+// parseLine parses a single line from the /proc/net/dev file. Header lines
+// must be filtered prior to calling this method.
+func (nd NetDev) parseLine(rawLine string) (*NetDevLine, error) {
+	parts := strings.SplitN(rawLine, ":", 2)
+	if len(parts) != 2 {
+		return nil, errors.New("invalid net/dev line, missing colon")
+	}
+	fields := strings.Fields(strings.TrimSpace(parts[1]))
+
+	var err error
+	line := &NetDevLine{}
+
+	// Interface Name
+	line.Name = strings.TrimSpace(parts[0])
+	if line.Name == "" {
+		return nil, errors.New("invalid net/dev line, empty interface name")
+	}
+
+	// RX
+	line.RxBytes, err = strconv.ParseUint(fields[0], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.RxPackets, err = strconv.ParseUint(fields[1], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.RxErrors, err = strconv.ParseUint(fields[2], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.RxDropped, err = strconv.ParseUint(fields[3], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.RxFIFO, err = strconv.ParseUint(fields[4], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.RxFrame, err = strconv.ParseUint(fields[5], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.RxCompressed, err = strconv.ParseUint(fields[6], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.RxMulticast, err = strconv.ParseUint(fields[7], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+
+	// TX
+	line.TxBytes, err = strconv.ParseUint(fields[8], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.TxPackets, err = strconv.ParseUint(fields[9], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.TxErrors, err = strconv.ParseUint(fields[10], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.TxDropped, err = strconv.ParseUint(fields[11], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.TxFIFO, err = strconv.ParseUint(fields[12], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.TxCollisions, err = strconv.ParseUint(fields[13], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.TxCarrier, err = strconv.ParseUint(fields[14], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+	line.TxCompressed, err = strconv.ParseUint(fields[15], 10, 64)
+	if err != nil {
+		return nil, err
+	}
+
+	return line, nil
+}
+
+// Total aggregates the values across interfaces and returns a new NetDevLine.
+// The Name field will be a sorted comma separated list of interface names.
+func (nd NetDev) Total() NetDevLine {
+	total := NetDevLine{}
+
+	names := make([]string, 0, len(nd))
+	for _, ifc := range nd {
+		names = append(names, ifc.Name)
+		total.RxBytes += ifc.RxBytes
+		total.RxPackets += ifc.RxPackets
+		total.RxPackets += ifc.RxPackets
+		total.RxErrors += ifc.RxErrors
+		total.RxDropped += ifc.RxDropped
+		total.RxFIFO += ifc.RxFIFO
+		total.RxFrame += ifc.RxFrame
+		total.RxCompressed += ifc.RxCompressed
+		total.RxMulticast += ifc.RxMulticast
+		total.TxBytes += ifc.TxBytes
+		total.TxPackets += ifc.TxPackets
+		total.TxErrors += ifc.TxErrors
+		total.TxDropped += ifc.TxDropped
+		total.TxFIFO += ifc.TxFIFO
+		total.TxCollisions += ifc.TxCollisions
+		total.TxCarrier += ifc.TxCarrier
+		total.TxCompressed += ifc.TxCompressed
+	}
+	sort.Strings(names)
+	total.Name = strings.Join(names, ", ")
+
+	return total
+}

+ 263 - 0
vendor/github.com/prometheus/procfs/nfs/nfs.go

@@ -0,0 +1,263 @@
+// Copyright 2018 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 nfs implements parsing of /proc/net/rpc/nfsd.
+// Fields are documented in https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/
+package nfs
+
+// ReplyCache models the "rc" line.
+type ReplyCache struct {
+	Hits    uint64
+	Misses  uint64
+	NoCache uint64
+}
+
+// FileHandles models the "fh" line.
+type FileHandles struct {
+	Stale        uint64
+	TotalLookups uint64
+	AnonLookups  uint64
+	DirNoCache   uint64
+	NoDirNoCache uint64
+}
+
+// InputOutput models the "io" line.
+type InputOutput struct {
+	Read  uint64
+	Write uint64
+}
+
+// Threads models the "th" line.
+type Threads struct {
+	Threads uint64
+	FullCnt uint64
+}
+
+// ReadAheadCache models the "ra" line.
+type ReadAheadCache struct {
+	CacheSize      uint64
+	CacheHistogram []uint64
+	NotFound       uint64
+}
+
+// Network models the "net" line.
+type Network struct {
+	NetCount   uint64
+	UDPCount   uint64
+	TCPCount   uint64
+	TCPConnect uint64
+}
+
+// ClientRPC models the nfs "rpc" line.
+type ClientRPC struct {
+	RPCCount        uint64
+	Retransmissions uint64
+	AuthRefreshes   uint64
+}
+
+// ServerRPC models the nfsd "rpc" line.
+type ServerRPC struct {
+	RPCCount uint64
+	BadCnt   uint64
+	BadFmt   uint64
+	BadAuth  uint64
+	BadcInt  uint64
+}
+
+// V2Stats models the "proc2" line.
+type V2Stats struct {
+	Null     uint64
+	GetAttr  uint64
+	SetAttr  uint64
+	Root     uint64
+	Lookup   uint64
+	ReadLink uint64
+	Read     uint64
+	WrCache  uint64
+	Write    uint64
+	Create   uint64
+	Remove   uint64
+	Rename   uint64
+	Link     uint64
+	SymLink  uint64
+	MkDir    uint64
+	RmDir    uint64
+	ReadDir  uint64
+	FsStat   uint64
+}
+
+// V3Stats models the "proc3" line.
+type V3Stats struct {
+	Null        uint64
+	GetAttr     uint64
+	SetAttr     uint64
+	Lookup      uint64
+	Access      uint64
+	ReadLink    uint64
+	Read        uint64
+	Write       uint64
+	Create      uint64
+	MkDir       uint64
+	SymLink     uint64
+	MkNod       uint64
+	Remove      uint64
+	RmDir       uint64
+	Rename      uint64
+	Link        uint64
+	ReadDir     uint64
+	ReadDirPlus uint64
+	FsStat      uint64
+	FsInfo      uint64
+	PathConf    uint64
+	Commit      uint64
+}
+
+// ClientV4Stats models the nfs "proc4" line.
+type ClientV4Stats struct {
+	Null               uint64
+	Read               uint64
+	Write              uint64
+	Commit             uint64
+	Open               uint64
+	OpenConfirm        uint64
+	OpenNoattr         uint64
+	OpenDowngrade      uint64
+	Close              uint64
+	Setattr            uint64
+	FsInfo             uint64
+	Renew              uint64
+	SetClientID        uint64
+	SetClientIDConfirm uint64
+	Lock               uint64
+	Lockt              uint64
+	Locku              uint64
+	Access             uint64
+	Getattr            uint64
+	Lookup             uint64
+	LookupRoot         uint64
+	Remove             uint64
+	Rename             uint64
+	Link               uint64
+	Symlink            uint64
+	Create             uint64
+	Pathconf           uint64
+	StatFs             uint64
+	ReadLink           uint64
+	ReadDir            uint64
+	ServerCaps         uint64
+	DelegReturn        uint64
+	GetACL             uint64
+	SetACL             uint64
+	FsLocations        uint64
+	ReleaseLockowner   uint64
+	Secinfo            uint64
+	FsidPresent        uint64
+	ExchangeID         uint64
+	CreateSession      uint64
+	DestroySession     uint64
+	Sequence           uint64
+	GetLeaseTime       uint64
+	ReclaimComplete    uint64
+	LayoutGet          uint64
+	GetDeviceInfo      uint64
+	LayoutCommit       uint64
+	LayoutReturn       uint64
+	SecinfoNoName      uint64
+	TestStateID        uint64
+	FreeStateID        uint64
+	GetDeviceList      uint64
+	BindConnToSession  uint64
+	DestroyClientID    uint64
+	Seek               uint64
+	Allocate           uint64
+	DeAllocate         uint64
+	LayoutStats        uint64
+	Clone              uint64
+}
+
+// ServerV4Stats models the nfsd "proc4" line.
+type ServerV4Stats struct {
+	Null     uint64
+	Compound uint64
+}
+
+// V4Ops models the "proc4ops" line: NFSv4 operations
+// Variable list, see:
+// v4.0 https://tools.ietf.org/html/rfc3010 (38 operations)
+// v4.1 https://tools.ietf.org/html/rfc5661 (58 operations)
+// v4.2 https://tools.ietf.org/html/draft-ietf-nfsv4-minorversion2-41 (71 operations)
+type V4Ops struct {
+	//Values       uint64 // Variable depending on v4.x sub-version. TODO: Will this always at least include the fields in this struct?
+	Op0Unused    uint64
+	Op1Unused    uint64
+	Op2Future    uint64
+	Access       uint64
+	Close        uint64
+	Commit       uint64
+	Create       uint64
+	DelegPurge   uint64
+	DelegReturn  uint64
+	GetAttr      uint64
+	GetFH        uint64
+	Link         uint64
+	Lock         uint64
+	Lockt        uint64
+	Locku        uint64
+	Lookup       uint64
+	LookupRoot   uint64
+	Nverify      uint64
+	Open         uint64
+	OpenAttr     uint64
+	OpenConfirm  uint64
+	OpenDgrd     uint64
+	PutFH        uint64
+	PutPubFH     uint64
+	PutRootFH    uint64
+	Read         uint64
+	ReadDir      uint64
+	ReadLink     uint64
+	Remove       uint64
+	Rename       uint64
+	Renew        uint64
+	RestoreFH    uint64
+	SaveFH       uint64
+	SecInfo      uint64
+	SetAttr      uint64
+	Verify       uint64
+	Write        uint64
+	RelLockOwner uint64
+}
+
+// ClientRPCStats models all stats from /proc/net/rpc/nfs.
+type ClientRPCStats struct {
+	Network       Network
+	ClientRPC     ClientRPC
+	V2Stats       V2Stats
+	V3Stats       V3Stats
+	ClientV4Stats ClientV4Stats
+}
+
+// ServerRPCStats models all stats from /proc/net/rpc/nfsd.
+type ServerRPCStats struct {
+	ReplyCache     ReplyCache
+	FileHandles    FileHandles
+	InputOutput    InputOutput
+	Threads        Threads
+	ReadAheadCache ReadAheadCache
+	Network        Network
+	ServerRPC      ServerRPC
+	V2Stats        V2Stats
+	V3Stats        V3Stats
+	ServerV4Stats  ServerV4Stats
+	V4Ops          V4Ops
+}

+ 317 - 0
vendor/github.com/prometheus/procfs/nfs/parse.go

@@ -0,0 +1,317 @@
+// Copyright 2018 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 nfs
+
+import (
+	"fmt"
+)
+
+func parseReplyCache(v []uint64) (ReplyCache, error) {
+	if len(v) != 3 {
+		return ReplyCache{}, fmt.Errorf("invalid ReplyCache line %q", v)
+	}
+
+	return ReplyCache{
+		Hits:    v[0],
+		Misses:  v[1],
+		NoCache: v[2],
+	}, nil
+}
+
+func parseFileHandles(v []uint64) (FileHandles, error) {
+	if len(v) != 5 {
+		return FileHandles{}, fmt.Errorf("invalid FileHandles, line %q", v)
+	}
+
+	return FileHandles{
+		Stale:        v[0],
+		TotalLookups: v[1],
+		AnonLookups:  v[2],
+		DirNoCache:   v[3],
+		NoDirNoCache: v[4],
+	}, nil
+}
+
+func parseInputOutput(v []uint64) (InputOutput, error) {
+	if len(v) != 2 {
+		return InputOutput{}, fmt.Errorf("invalid InputOutput line %q", v)
+	}
+
+	return InputOutput{
+		Read:  v[0],
+		Write: v[1],
+	}, nil
+}
+
+func parseThreads(v []uint64) (Threads, error) {
+	if len(v) != 2 {
+		return Threads{}, fmt.Errorf("invalid Threads line %q", v)
+	}
+
+	return Threads{
+		Threads: v[0],
+		FullCnt: v[1],
+	}, nil
+}
+
+func parseReadAheadCache(v []uint64) (ReadAheadCache, error) {
+	if len(v) != 12 {
+		return ReadAheadCache{}, fmt.Errorf("invalid ReadAheadCache line %q", v)
+	}
+
+	return ReadAheadCache{
+		CacheSize:      v[0],
+		CacheHistogram: v[1:11],
+		NotFound:       v[11],
+	}, nil
+}
+
+func parseNetwork(v []uint64) (Network, error) {
+	if len(v) != 4 {
+		return Network{}, fmt.Errorf("invalid Network line %q", v)
+	}
+
+	return Network{
+		NetCount:   v[0],
+		UDPCount:   v[1],
+		TCPCount:   v[2],
+		TCPConnect: v[3],
+	}, nil
+}
+
+func parseServerRPC(v []uint64) (ServerRPC, error) {
+	if len(v) != 5 {
+		return ServerRPC{}, fmt.Errorf("invalid RPC line %q", v)
+	}
+
+	return ServerRPC{
+		RPCCount: v[0],
+		BadCnt:   v[1],
+		BadFmt:   v[2],
+		BadAuth:  v[3],
+		BadcInt:  v[4],
+	}, nil
+}
+
+func parseClientRPC(v []uint64) (ClientRPC, error) {
+	if len(v) != 3 {
+		return ClientRPC{}, fmt.Errorf("invalid RPC line %q", v)
+	}
+
+	return ClientRPC{
+		RPCCount:        v[0],
+		Retransmissions: v[1],
+		AuthRefreshes:   v[2],
+	}, nil
+}
+
+func parseV2Stats(v []uint64) (V2Stats, error) {
+	values := int(v[0])
+	if len(v[1:]) != values || values != 18 {
+		return V2Stats{}, fmt.Errorf("invalid V2Stats line %q", v)
+	}
+
+	return V2Stats{
+		Null:     v[1],
+		GetAttr:  v[2],
+		SetAttr:  v[3],
+		Root:     v[4],
+		Lookup:   v[5],
+		ReadLink: v[6],
+		Read:     v[7],
+		WrCache:  v[8],
+		Write:    v[9],
+		Create:   v[10],
+		Remove:   v[11],
+		Rename:   v[12],
+		Link:     v[13],
+		SymLink:  v[14],
+		MkDir:    v[15],
+		RmDir:    v[16],
+		ReadDir:  v[17],
+		FsStat:   v[18],
+	}, nil
+}
+
+func parseV3Stats(v []uint64) (V3Stats, error) {
+	values := int(v[0])
+	if len(v[1:]) != values || values != 22 {
+		return V3Stats{}, fmt.Errorf("invalid V3Stats line %q", v)
+	}
+
+	return V3Stats{
+		Null:        v[1],
+		GetAttr:     v[2],
+		SetAttr:     v[3],
+		Lookup:      v[4],
+		Access:      v[5],
+		ReadLink:    v[6],
+		Read:        v[7],
+		Write:       v[8],
+		Create:      v[9],
+		MkDir:       v[10],
+		SymLink:     v[11],
+		MkNod:       v[12],
+		Remove:      v[13],
+		RmDir:       v[14],
+		Rename:      v[15],
+		Link:        v[16],
+		ReadDir:     v[17],
+		ReadDirPlus: v[18],
+		FsStat:      v[19],
+		FsInfo:      v[20],
+		PathConf:    v[21],
+		Commit:      v[22],
+	}, nil
+}
+
+func parseClientV4Stats(v []uint64) (ClientV4Stats, error) {
+	values := int(v[0])
+	if len(v[1:]) != values {
+		return ClientV4Stats{}, fmt.Errorf("invalid ClientV4Stats line %q", v)
+	}
+
+	// This function currently supports mapping 59 NFS v4 client stats.  Older
+	// kernels may emit fewer stats, so we must detect this and pad out the
+	// values to match the expected slice size.
+	if values < 59 {
+		newValues := make([]uint64, 60)
+		copy(newValues, v)
+		v = newValues
+	}
+
+	return ClientV4Stats{
+		Null:               v[1],
+		Read:               v[2],
+		Write:              v[3],
+		Commit:             v[4],
+		Open:               v[5],
+		OpenConfirm:        v[6],
+		OpenNoattr:         v[7],
+		OpenDowngrade:      v[8],
+		Close:              v[9],
+		Setattr:            v[10],
+		FsInfo:             v[11],
+		Renew:              v[12],
+		SetClientID:        v[13],
+		SetClientIDConfirm: v[14],
+		Lock:               v[15],
+		Lockt:              v[16],
+		Locku:              v[17],
+		Access:             v[18],
+		Getattr:            v[19],
+		Lookup:             v[20],
+		LookupRoot:         v[21],
+		Remove:             v[22],
+		Rename:             v[23],
+		Link:               v[24],
+		Symlink:            v[25],
+		Create:             v[26],
+		Pathconf:           v[27],
+		StatFs:             v[28],
+		ReadLink:           v[29],
+		ReadDir:            v[30],
+		ServerCaps:         v[31],
+		DelegReturn:        v[32],
+		GetACL:             v[33],
+		SetACL:             v[34],
+		FsLocations:        v[35],
+		ReleaseLockowner:   v[36],
+		Secinfo:            v[37],
+		FsidPresent:        v[38],
+		ExchangeID:         v[39],
+		CreateSession:      v[40],
+		DestroySession:     v[41],
+		Sequence:           v[42],
+		GetLeaseTime:       v[43],
+		ReclaimComplete:    v[44],
+		LayoutGet:          v[45],
+		GetDeviceInfo:      v[46],
+		LayoutCommit:       v[47],
+		LayoutReturn:       v[48],
+		SecinfoNoName:      v[49],
+		TestStateID:        v[50],
+		FreeStateID:        v[51],
+		GetDeviceList:      v[52],
+		BindConnToSession:  v[53],
+		DestroyClientID:    v[54],
+		Seek:               v[55],
+		Allocate:           v[56],
+		DeAllocate:         v[57],
+		LayoutStats:        v[58],
+		Clone:              v[59],
+	}, nil
+}
+
+func parseServerV4Stats(v []uint64) (ServerV4Stats, error) {
+	values := int(v[0])
+	if len(v[1:]) != values || values != 2 {
+		return ServerV4Stats{}, fmt.Errorf("invalid V4Stats line %q", v)
+	}
+
+	return ServerV4Stats{
+		Null:     v[1],
+		Compound: v[2],
+	}, nil
+}
+
+func parseV4Ops(v []uint64) (V4Ops, error) {
+	values := int(v[0])
+	if len(v[1:]) != values || values < 39 {
+		return V4Ops{}, fmt.Errorf("invalid V4Ops line %q", v)
+	}
+
+	stats := V4Ops{
+		Op0Unused:    v[1],
+		Op1Unused:    v[2],
+		Op2Future:    v[3],
+		Access:       v[4],
+		Close:        v[5],
+		Commit:       v[6],
+		Create:       v[7],
+		DelegPurge:   v[8],
+		DelegReturn:  v[9],
+		GetAttr:      v[10],
+		GetFH:        v[11],
+		Link:         v[12],
+		Lock:         v[13],
+		Lockt:        v[14],
+		Locku:        v[15],
+		Lookup:       v[16],
+		LookupRoot:   v[17],
+		Nverify:      v[18],
+		Open:         v[19],
+		OpenAttr:     v[20],
+		OpenConfirm:  v[21],
+		OpenDgrd:     v[22],
+		PutFH:        v[23],
+		PutPubFH:     v[24],
+		PutRootFH:    v[25],
+		Read:         v[26],
+		ReadDir:      v[27],
+		ReadLink:     v[28],
+		Remove:       v[29],
+		Rename:       v[30],
+		Renew:        v[31],
+		RestoreFH:    v[32],
+		SaveFH:       v[33],
+		SecInfo:      v[34],
+		SetAttr:      v[35],
+		Verify:       v[36],
+		Write:        v[37],
+		RelLockOwner: v[38],
+	}
+
+	return stats, nil
+}

+ 67 - 0
vendor/github.com/prometheus/procfs/nfs/parse_nfs.go

@@ -0,0 +1,67 @@
+// Copyright 2018 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 nfs
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"strings"
+
+	"github.com/prometheus/procfs/internal/util"
+)
+
+// ParseClientRPCStats returns stats read from /proc/net/rpc/nfs
+func ParseClientRPCStats(r io.Reader) (*ClientRPCStats, error) {
+	stats := &ClientRPCStats{}
+
+	scanner := bufio.NewScanner(r)
+	for scanner.Scan() {
+		line := scanner.Text()
+		parts := strings.Fields(scanner.Text())
+		// require at least <key> <value>
+		if len(parts) < 2 {
+			return nil, fmt.Errorf("invalid NFS metric line %q", line)
+		}
+
+		values, err := util.ParseUint64s(parts[1:])
+		if err != nil {
+			return nil, fmt.Errorf("error parsing NFS metric line: %s", err)
+		}
+
+		switch metricLine := parts[0]; metricLine {
+		case "net":
+			stats.Network, err = parseNetwork(values)
+		case "rpc":
+			stats.ClientRPC, err = parseClientRPC(values)
+		case "proc2":
+			stats.V2Stats, err = parseV2Stats(values)
+		case "proc3":
+			stats.V3Stats, err = parseV3Stats(values)
+		case "proc4":
+			stats.ClientV4Stats, err = parseClientV4Stats(values)
+		default:
+			return nil, fmt.Errorf("unknown NFS metric line %q", metricLine)
+		}
+		if err != nil {
+			return nil, fmt.Errorf("errors parsing NFS metric line: %s", err)
+		}
+	}
+
+	if err := scanner.Err(); err != nil {
+		return nil, fmt.Errorf("error scanning NFS file: %s", err)
+	}
+
+	return stats, nil
+}

+ 89 - 0
vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go

@@ -0,0 +1,89 @@
+// Copyright 2018 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 nfs
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"strings"
+
+	"github.com/prometheus/procfs/internal/util"
+)
+
+// ParseServerRPCStats returns stats read from /proc/net/rpc/nfsd
+func ParseServerRPCStats(r io.Reader) (*ServerRPCStats, error) {
+	stats := &ServerRPCStats{}
+
+	scanner := bufio.NewScanner(r)
+	for scanner.Scan() {
+		line := scanner.Text()
+		parts := strings.Fields(scanner.Text())
+		// require at least <key> <value>
+		if len(parts) < 2 {
+			return nil, fmt.Errorf("invalid NFSd metric line %q", line)
+		}
+		label := parts[0]
+
+		var values []uint64
+		var err error
+		if label == "th" {
+			if len(parts) < 3 {
+				return nil, fmt.Errorf("invalid NFSd th metric line %q", line)
+			}
+			values, err = util.ParseUint64s(parts[1:3])
+		} else {
+			values, err = util.ParseUint64s(parts[1:])
+		}
+		if err != nil {
+			return nil, fmt.Errorf("error parsing NFSd metric line: %s", err)
+		}
+
+		switch metricLine := parts[0]; metricLine {
+		case "rc":
+			stats.ReplyCache, err = parseReplyCache(values)
+		case "fh":
+			stats.FileHandles, err = parseFileHandles(values)
+		case "io":
+			stats.InputOutput, err = parseInputOutput(values)
+		case "th":
+			stats.Threads, err = parseThreads(values)
+		case "ra":
+			stats.ReadAheadCache, err = parseReadAheadCache(values)
+		case "net":
+			stats.Network, err = parseNetwork(values)
+		case "rpc":
+			stats.ServerRPC, err = parseServerRPC(values)
+		case "proc2":
+			stats.V2Stats, err = parseV2Stats(values)
+		case "proc3":
+			stats.V3Stats, err = parseV3Stats(values)
+		case "proc4":
+			stats.ServerV4Stats, err = parseServerV4Stats(values)
+		case "proc4ops":
+			stats.V4Ops, err = parseV4Ops(values)
+		default:
+			return nil, fmt.Errorf("unknown NFSd metric line %q", metricLine)
+		}
+		if err != nil {
+			return nil, fmt.Errorf("errors parsing NFSd metric line: %s", err)
+		}
+	}
+
+	if err := scanner.Err(); err != nil {
+		return nil, fmt.Errorf("error scanning NFSd file: %s", err)
+	}
+
+	return stats, nil
+}

+ 27 - 1
vendor/github.com/prometheus/procfs/proc.go

@@ -1,6 +1,20 @@
+// Copyright 2018 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 procfs
 package procfs
 
 
 import (
 import (
+	"bytes"
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
@@ -113,7 +127,7 @@ func (p Proc) CmdLine() ([]string, error) {
 		return []string{}, nil
 		return []string{}, nil
 	}
 	}
 
 
-	return strings.Split(string(data[:len(data)-1]), string(byte(0))), nil
+	return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
 }
 }
 
 
 // Comm returns the command name of a process.
 // Comm returns the command name of a process.
@@ -192,6 +206,18 @@ func (p Proc) FileDescriptorsLen() (int, error) {
 	return len(fds), nil
 	return len(fds), nil
 }
 }
 
 
+// MountStats retrieves statistics and configuration for mount points in a
+// process's namespace.
+func (p Proc) MountStats() ([]*Mount, error) {
+	f, err := os.Open(p.path("mountstats"))
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	return parseMountStats(f)
+}
+
 func (p Proc) fileDescriptors() ([]string, error) {
 func (p Proc) fileDescriptors() ([]string, error) {
 	d, err := os.Open(p.path("fd"))
 	d, err := os.Open(p.path("fd"))
 	if err != nil {
 	if err != nil {

+ 14 - 4
vendor/github.com/prometheus/procfs/proc_io.go

@@ -1,3 +1,16 @@
+// Copyright 2018 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 procfs
 package procfs
 
 
 import (
 import (
@@ -47,9 +60,6 @@ func (p Proc) NewIO() (ProcIO, error) {
 
 
 	_, err = fmt.Sscanf(string(data), ioFormat, &pio.RChar, &pio.WChar, &pio.SyscR,
 	_, err = fmt.Sscanf(string(data), ioFormat, &pio.RChar, &pio.WChar, &pio.SyscR,
 		&pio.SyscW, &pio.ReadBytes, &pio.WriteBytes, &pio.CancelledWriteBytes)
 		&pio.SyscW, &pio.ReadBytes, &pio.WriteBytes, &pio.CancelledWriteBytes)
-	if err != nil {
-		return pio, err
-	}
 
 
-	return pio, nil
+	return pio, err
 }
 }

+ 32 - 19
vendor/github.com/prometheus/procfs/proc_limits.go

@@ -1,3 +1,16 @@
+// Copyright 2018 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 procfs
 package procfs
 
 
 import (
 import (
@@ -13,46 +26,46 @@ import (
 // http://man7.org/linux/man-pages/man2/getrlimit.2.html.
 // http://man7.org/linux/man-pages/man2/getrlimit.2.html.
 type ProcLimits struct {
 type ProcLimits struct {
 	// CPU time limit in seconds.
 	// CPU time limit in seconds.
-	CPUTime int
+	CPUTime int64
 	// Maximum size of files that the process may create.
 	// Maximum size of files that the process may create.
-	FileSize int
+	FileSize int64
 	// Maximum size of the process's data segment (initialized data,
 	// Maximum size of the process's data segment (initialized data,
 	// uninitialized data, and heap).
 	// uninitialized data, and heap).
-	DataSize int
+	DataSize int64
 	// Maximum size of the process stack in bytes.
 	// Maximum size of the process stack in bytes.
-	StackSize int
+	StackSize int64
 	// Maximum size of a core file.
 	// Maximum size of a core file.
-	CoreFileSize int
+	CoreFileSize int64
 	// Limit of the process's resident set in pages.
 	// Limit of the process's resident set in pages.
-	ResidentSet int
+	ResidentSet int64
 	// Maximum number of processes that can be created for the real user ID of
 	// Maximum number of processes that can be created for the real user ID of
 	// the calling process.
 	// the calling process.
-	Processes int
+	Processes int64
 	// Value one greater than the maximum file descriptor number that can be
 	// Value one greater than the maximum file descriptor number that can be
 	// opened by this process.
 	// opened by this process.
-	OpenFiles int
+	OpenFiles int64
 	// Maximum number of bytes of memory that may be locked into RAM.
 	// Maximum number of bytes of memory that may be locked into RAM.
-	LockedMemory int
+	LockedMemory int64
 	// Maximum size of the process's virtual memory address space in bytes.
 	// Maximum size of the process's virtual memory address space in bytes.
-	AddressSpace int
+	AddressSpace int64
 	// Limit on the combined number of flock(2) locks and fcntl(2) leases that
 	// Limit on the combined number of flock(2) locks and fcntl(2) leases that
 	// this process may establish.
 	// this process may establish.
-	FileLocks int
+	FileLocks int64
 	// Limit of signals that may be queued for the real user ID of the calling
 	// Limit of signals that may be queued for the real user ID of the calling
 	// process.
 	// process.
-	PendingSignals int
+	PendingSignals int64
 	// Limit on the number of bytes that can be allocated for POSIX message
 	// Limit on the number of bytes that can be allocated for POSIX message
 	// queues for the real user ID of the calling process.
 	// queues for the real user ID of the calling process.
-	MsqqueueSize int
+	MsqqueueSize int64
 	// Limit of the nice priority set using setpriority(2) or nice(2).
 	// Limit of the nice priority set using setpriority(2) or nice(2).
-	NicePriority int
+	NicePriority int64
 	// Limit of the real-time priority set using sched_setscheduler(2) or
 	// Limit of the real-time priority set using sched_setscheduler(2) or
 	// sched_setparam(2).
 	// sched_setparam(2).
-	RealtimePriority int
+	RealtimePriority int64
 	// Limit (in microseconds) on the amount of CPU time that a process
 	// Limit (in microseconds) on the amount of CPU time that a process
 	// scheduled under a real-time scheduling policy may consume without making
 	// scheduled under a real-time scheduling policy may consume without making
 	// a blocking system call.
 	// a blocking system call.
-	RealtimeTimeout int
+	RealtimeTimeout int64
 }
 }
 
 
 const (
 const (
@@ -125,13 +138,13 @@ func (p Proc) NewLimits() (ProcLimits, error) {
 	return l, s.Err()
 	return l, s.Err()
 }
 }
 
 
-func parseInt(s string) (int, error) {
+func parseInt(s string) (int64, error) {
 	if s == limitsUnlimited {
 	if s == limitsUnlimited {
 		return -1, nil
 		return -1, nil
 	}
 	}
-	i, err := strconv.ParseInt(s, 10, 32)
+	i, err := strconv.ParseInt(s, 10, 64)
 	if err != nil {
 	if err != nil {
 		return 0, fmt.Errorf("couldn't parse value %s: %s", s, err)
 		return 0, fmt.Errorf("couldn't parse value %s: %s", s, err)
 	}
 	}
-	return int(i), nil
+	return i, nil
 }
 }

+ 68 - 0
vendor/github.com/prometheus/procfs/proc_ns.go

@@ -0,0 +1,68 @@
+// Copyright 2018 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 procfs
+
+import (
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+)
+
+// Namespace represents a single namespace of a process.
+type Namespace struct {
+	Type  string // Namespace type.
+	Inode uint32 // Inode number of the namespace. If two processes are in the same namespace their inodes will match.
+}
+
+// Namespaces contains all of the namespaces that the process is contained in.
+type Namespaces map[string]Namespace
+
+// NewNamespaces reads from /proc/[pid/ns/* to get the namespaces of which the
+// process is a member.
+func (p Proc) NewNamespaces() (Namespaces, error) {
+	d, err := os.Open(p.path("ns"))
+	if err != nil {
+		return nil, err
+	}
+	defer d.Close()
+
+	names, err := d.Readdirnames(-1)
+	if err != nil {
+		return nil, fmt.Errorf("failed to read contents of ns dir: %v", err)
+	}
+
+	ns := make(Namespaces, len(names))
+	for _, name := range names {
+		target, err := os.Readlink(p.path("ns", name))
+		if err != nil {
+			return nil, err
+		}
+
+		fields := strings.SplitN(target, ":", 2)
+		if len(fields) != 2 {
+			return nil, fmt.Errorf("failed to parse namespace type and inode from '%v'", target)
+		}
+
+		typ := fields[0]
+		inode, err := strconv.ParseUint(strings.Trim(fields[1], "[]"), 10, 32)
+		if err != nil {
+			return nil, fmt.Errorf("failed to parse inode from '%v': %v", fields[1], err)
+		}
+
+		ns[name] = Namespace{typ, uint32(inode)}
+	}
+
+	return ns, nil
+}

+ 13 - 0
vendor/github.com/prometheus/procfs/proc_stat.go

@@ -1,3 +1,16 @@
+// Copyright 2018 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 procfs
 package procfs
 
 
 import (
 import (

+ 191 - 15
vendor/github.com/prometheus/procfs/stat.go

@@ -1,17 +1,81 @@
+// Copyright 2018 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 procfs
 package procfs
 
 
 import (
 import (
 	"bufio"
 	"bufio"
 	"fmt"
 	"fmt"
+	"io"
 	"os"
 	"os"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 )
 )
 
 
+// CPUStat shows how much time the cpu spend in various stages.
+type CPUStat struct {
+	User      float64
+	Nice      float64
+	System    float64
+	Idle      float64
+	Iowait    float64
+	IRQ       float64
+	SoftIRQ   float64
+	Steal     float64
+	Guest     float64
+	GuestNice float64
+}
+
+// SoftIRQStat represent the softirq statistics as exported in the procfs stat file.
+// A nice introduction can be found at https://0xax.gitbooks.io/linux-insides/content/interrupts/interrupts-9.html
+// It is possible to get per-cpu stats by reading /proc/softirqs
+type SoftIRQStat struct {
+	Hi          uint64
+	Timer       uint64
+	NetTx       uint64
+	NetRx       uint64
+	Block       uint64
+	BlockIoPoll uint64
+	Tasklet     uint64
+	Sched       uint64
+	Hrtimer     uint64
+	Rcu         uint64
+}
+
 // Stat represents kernel/system statistics.
 // Stat represents kernel/system statistics.
 type Stat struct {
 type Stat struct {
 	// Boot time in seconds since the Epoch.
 	// Boot time in seconds since the Epoch.
-	BootTime int64
+	BootTime uint64
+	// Summed up cpu statistics.
+	CPUTotal CPUStat
+	// Per-CPU statistics.
+	CPU []CPUStat
+	// Number of times interrupts were handled, which contains numbered and unnumbered IRQs.
+	IRQTotal uint64
+	// Number of times a numbered IRQ was triggered.
+	IRQ []uint64
+	// Number of times a context switch happened.
+	ContextSwitches uint64
+	// Number of times a process was created.
+	ProcessCreated uint64
+	// Number of processes currently running.
+	ProcessesRunning uint64
+	// Number of processes currently blocked (waiting for IO).
+	ProcessesBlocked uint64
+	// Number of times a softirq was scheduled.
+	SoftIRQTotal uint64
+	// Detailed softirq statistics.
+	SoftIRQ SoftIRQStat
 }
 }
 
 
 // NewStat returns kernel/system statistics read from /proc/stat.
 // NewStat returns kernel/system statistics read from /proc/stat.
@@ -24,33 +88,145 @@ func NewStat() (Stat, error) {
 	return fs.NewStat()
 	return fs.NewStat()
 }
 }
 
 
+// Parse a cpu statistics line and returns the CPUStat struct plus the cpu id (or -1 for the overall sum).
+func parseCPUStat(line string) (CPUStat, int64, error) {
+	cpuStat := CPUStat{}
+	var cpu string
+
+	count, err := fmt.Sscanf(line, "%s %f %f %f %f %f %f %f %f %f %f",
+		&cpu,
+		&cpuStat.User, &cpuStat.Nice, &cpuStat.System, &cpuStat.Idle,
+		&cpuStat.Iowait, &cpuStat.IRQ, &cpuStat.SoftIRQ, &cpuStat.Steal,
+		&cpuStat.Guest, &cpuStat.GuestNice)
+
+	if err != nil && err != io.EOF {
+		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): %s", line, err)
+	}
+	if count == 0 {
+		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): 0 elements parsed", line)
+	}
+
+	cpuStat.User /= userHZ
+	cpuStat.Nice /= userHZ
+	cpuStat.System /= userHZ
+	cpuStat.Idle /= userHZ
+	cpuStat.Iowait /= userHZ
+	cpuStat.IRQ /= userHZ
+	cpuStat.SoftIRQ /= userHZ
+	cpuStat.Steal /= userHZ
+	cpuStat.Guest /= userHZ
+	cpuStat.GuestNice /= userHZ
+
+	if cpu == "cpu" {
+		return cpuStat, -1, nil
+	}
+
+	cpuID, err := strconv.ParseInt(cpu[3:], 10, 64)
+	if err != nil {
+		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu/cpuid): %s", line, err)
+	}
+
+	return cpuStat, cpuID, nil
+}
+
+// Parse a softirq line.
+func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) {
+	softIRQStat := SoftIRQStat{}
+	var total uint64
+	var prefix string
+
+	_, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d",
+		&prefix, &total,
+		&softIRQStat.Hi, &softIRQStat.Timer, &softIRQStat.NetTx, &softIRQStat.NetRx,
+		&softIRQStat.Block, &softIRQStat.BlockIoPoll,
+		&softIRQStat.Tasklet, &softIRQStat.Sched,
+		&softIRQStat.Hrtimer, &softIRQStat.Rcu)
+
+	if err != nil {
+		return SoftIRQStat{}, 0, fmt.Errorf("couldn't parse %s (softirq): %s", line, err)
+	}
+
+	return softIRQStat, total, nil
+}
+
 // NewStat returns an information about current kernel/system statistics.
 // NewStat returns an information about current kernel/system statistics.
 func (fs FS) NewStat() (Stat, error) {
 func (fs FS) NewStat() (Stat, error) {
+	// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+
 	f, err := os.Open(fs.Path("stat"))
 	f, err := os.Open(fs.Path("stat"))
 	if err != nil {
 	if err != nil {
 		return Stat{}, err
 		return Stat{}, err
 	}
 	}
 	defer f.Close()
 	defer f.Close()
 
 
-	s := bufio.NewScanner(f)
-	for s.Scan() {
-		line := s.Text()
-		if !strings.HasPrefix(line, "btime") {
+	stat := Stat{}
+
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		line := scanner.Text()
+		parts := strings.Fields(scanner.Text())
+		// require at least <key> <value>
+		if len(parts) < 2 {
 			continue
 			continue
 		}
 		}
-		fields := strings.Fields(line)
-		if len(fields) != 2 {
-			return Stat{}, fmt.Errorf("couldn't parse %s line %s", f.Name(), line)
-		}
-		i, err := strconv.ParseInt(fields[1], 10, 32)
-		if err != nil {
-			return Stat{}, fmt.Errorf("couldn't parse %s: %s", fields[1], err)
+		switch {
+		case parts[0] == "btime":
+			if stat.BootTime, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+				return Stat{}, fmt.Errorf("couldn't parse %s (btime): %s", parts[1], err)
+			}
+		case parts[0] == "intr":
+			if stat.IRQTotal, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+				return Stat{}, fmt.Errorf("couldn't parse %s (intr): %s", parts[1], err)
+			}
+			numberedIRQs := parts[2:]
+			stat.IRQ = make([]uint64, len(numberedIRQs))
+			for i, count := range numberedIRQs {
+				if stat.IRQ[i], err = strconv.ParseUint(count, 10, 64); err != nil {
+					return Stat{}, fmt.Errorf("couldn't parse %s (intr%d): %s", count, i, err)
+				}
+			}
+		case parts[0] == "ctxt":
+			if stat.ContextSwitches, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+				return Stat{}, fmt.Errorf("couldn't parse %s (ctxt): %s", parts[1], err)
+			}
+		case parts[0] == "processes":
+			if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+				return Stat{}, fmt.Errorf("couldn't parse %s (processes): %s", parts[1], err)
+			}
+		case parts[0] == "procs_running":
+			if stat.ProcessesRunning, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+				return Stat{}, fmt.Errorf("couldn't parse %s (procs_running): %s", parts[1], err)
+			}
+		case parts[0] == "procs_blocked":
+			if stat.ProcessesBlocked, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+				return Stat{}, fmt.Errorf("couldn't parse %s (procs_blocked): %s", parts[1], err)
+			}
+		case parts[0] == "softirq":
+			softIRQStats, total, err := parseSoftIRQStat(line)
+			if err != nil {
+				return Stat{}, err
+			}
+			stat.SoftIRQTotal = total
+			stat.SoftIRQ = softIRQStats
+		case strings.HasPrefix(parts[0], "cpu"):
+			cpuStat, cpuID, err := parseCPUStat(line)
+			if err != nil {
+				return Stat{}, err
+			}
+			if cpuID == -1 {
+				stat.CPUTotal = cpuStat
+			} else {
+				for int64(len(stat.CPU)) <= cpuID {
+					stat.CPU = append(stat.CPU, CPUStat{})
+				}
+				stat.CPU[cpuID] = cpuStat
+			}
 		}
 		}
-		return Stat{BootTime: i}, nil
 	}
 	}
-	if err := s.Err(); err != nil {
+
+	if err := scanner.Err(); err != nil {
 		return Stat{}, fmt.Errorf("couldn't parse %s: %s", f.Name(), err)
 		return Stat{}, fmt.Errorf("couldn't parse %s: %s", f.Name(), err)
 	}
 	}
 
 
-	return Stat{}, fmt.Errorf("couldn't parse %s, missing btime", f.Name())
+	return stat, nil
 }
 }

+ 187 - 0
vendor/github.com/prometheus/procfs/xfrm.go

@@ -0,0 +1,187 @@
+// Copyright 2017 Prometheus Team
+// 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 procfs
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+)
+
+// XfrmStat models the contents of /proc/net/xfrm_stat.
+type XfrmStat struct {
+	// All errors which are not matched by other
+	XfrmInError int
+	// No buffer is left
+	XfrmInBufferError int
+	// Header Error
+	XfrmInHdrError int
+	// No state found
+	// i.e. either inbound SPI, address, or IPSEC protocol at SA is wrong
+	XfrmInNoStates int
+	// Transformation protocol specific error
+	// e.g. SA Key is wrong
+	XfrmInStateProtoError int
+	// Transformation mode specific error
+	XfrmInStateModeError int
+	// Sequence error
+	// e.g. sequence number is out of window
+	XfrmInStateSeqError int
+	// State is expired
+	XfrmInStateExpired int
+	// State has mismatch option
+	// e.g. UDP encapsulation type is mismatched
+	XfrmInStateMismatch int
+	// State is invalid
+	XfrmInStateInvalid int
+	// No matching template for states
+	// e.g. Inbound SAs are correct but SP rule is wrong
+	XfrmInTmplMismatch int
+	// No policy is found for states
+	// e.g. Inbound SAs are correct but no SP is found
+	XfrmInNoPols int
+	// Policy discards
+	XfrmInPolBlock int
+	// Policy error
+	XfrmInPolError int
+	// All errors which are not matched by others
+	XfrmOutError int
+	// Bundle generation error
+	XfrmOutBundleGenError int
+	// Bundle check error
+	XfrmOutBundleCheckError int
+	// No state was found
+	XfrmOutNoStates int
+	// Transformation protocol specific error
+	XfrmOutStateProtoError int
+	// Transportation mode specific error
+	XfrmOutStateModeError int
+	// Sequence error
+	// i.e sequence number overflow
+	XfrmOutStateSeqError int
+	// State is expired
+	XfrmOutStateExpired int
+	// Policy discads
+	XfrmOutPolBlock int
+	// Policy is dead
+	XfrmOutPolDead int
+	// Policy Error
+	XfrmOutPolError     int
+	XfrmFwdHdrError     int
+	XfrmOutStateInvalid int
+	XfrmAcquireError    int
+}
+
+// NewXfrmStat reads the xfrm_stat statistics.
+func NewXfrmStat() (XfrmStat, error) {
+	fs, err := NewFS(DefaultMountPoint)
+	if err != nil {
+		return XfrmStat{}, err
+	}
+
+	return fs.NewXfrmStat()
+}
+
+// NewXfrmStat reads the xfrm_stat statistics from the 'proc' filesystem.
+func (fs FS) NewXfrmStat() (XfrmStat, error) {
+	file, err := os.Open(fs.Path("net/xfrm_stat"))
+	if err != nil {
+		return XfrmStat{}, err
+	}
+	defer file.Close()
+
+	var (
+		x = XfrmStat{}
+		s = bufio.NewScanner(file)
+	)
+
+	for s.Scan() {
+		fields := strings.Fields(s.Text())
+
+		if len(fields) != 2 {
+			return XfrmStat{}, fmt.Errorf(
+				"couldnt parse %s line %s", file.Name(), s.Text())
+		}
+
+		name := fields[0]
+		value, err := strconv.Atoi(fields[1])
+		if err != nil {
+			return XfrmStat{}, err
+		}
+
+		switch name {
+		case "XfrmInError":
+			x.XfrmInError = value
+		case "XfrmInBufferError":
+			x.XfrmInBufferError = value
+		case "XfrmInHdrError":
+			x.XfrmInHdrError = value
+		case "XfrmInNoStates":
+			x.XfrmInNoStates = value
+		case "XfrmInStateProtoError":
+			x.XfrmInStateProtoError = value
+		case "XfrmInStateModeError":
+			x.XfrmInStateModeError = value
+		case "XfrmInStateSeqError":
+			x.XfrmInStateSeqError = value
+		case "XfrmInStateExpired":
+			x.XfrmInStateExpired = value
+		case "XfrmInStateInvalid":
+			x.XfrmInStateInvalid = value
+		case "XfrmInTmplMismatch":
+			x.XfrmInTmplMismatch = value
+		case "XfrmInNoPols":
+			x.XfrmInNoPols = value
+		case "XfrmInPolBlock":
+			x.XfrmInPolBlock = value
+		case "XfrmInPolError":
+			x.XfrmInPolError = value
+		case "XfrmOutError":
+			x.XfrmOutError = value
+		case "XfrmInStateMismatch":
+			x.XfrmInStateMismatch = value
+		case "XfrmOutBundleGenError":
+			x.XfrmOutBundleGenError = value
+		case "XfrmOutBundleCheckError":
+			x.XfrmOutBundleCheckError = value
+		case "XfrmOutNoStates":
+			x.XfrmOutNoStates = value
+		case "XfrmOutStateProtoError":
+			x.XfrmOutStateProtoError = value
+		case "XfrmOutStateModeError":
+			x.XfrmOutStateModeError = value
+		case "XfrmOutStateSeqError":
+			x.XfrmOutStateSeqError = value
+		case "XfrmOutStateExpired":
+			x.XfrmOutStateExpired = value
+		case "XfrmOutPolBlock":
+			x.XfrmOutPolBlock = value
+		case "XfrmOutPolDead":
+			x.XfrmOutPolDead = value
+		case "XfrmOutPolError":
+			x.XfrmOutPolError = value
+		case "XfrmFwdHdrError":
+			x.XfrmFwdHdrError = value
+		case "XfrmOutStateInvalid":
+			x.XfrmOutStateInvalid = value
+		case "XfrmAcquireError":
+			x.XfrmAcquireError = value
+		}
+
+	}
+
+	return x, s.Err()
+}

+ 330 - 0
vendor/github.com/prometheus/procfs/xfs/parse.go

@@ -0,0 +1,330 @@
+// Copyright 2017 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 xfs
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"strings"
+
+	"github.com/prometheus/procfs/internal/util"
+)
+
+// ParseStats parses a Stats from an input io.Reader, using the format
+// found in /proc/fs/xfs/stat.
+func ParseStats(r io.Reader) (*Stats, error) {
+	const (
+		// Fields parsed into stats structures.
+		fieldExtentAlloc = "extent_alloc"
+		fieldAbt         = "abt"
+		fieldBlkMap      = "blk_map"
+		fieldBmbt        = "bmbt"
+		fieldDir         = "dir"
+		fieldTrans       = "trans"
+		fieldIg          = "ig"
+		fieldLog         = "log"
+		fieldRw          = "rw"
+		fieldAttr        = "attr"
+		fieldIcluster    = "icluster"
+		fieldVnodes      = "vnodes"
+		fieldBuf         = "buf"
+		fieldXpc         = "xpc"
+
+		// Unimplemented at this time due to lack of documentation.
+		fieldPushAil = "push_ail"
+		fieldXstrat  = "xstrat"
+		fieldAbtb2   = "abtb2"
+		fieldAbtc2   = "abtc2"
+		fieldBmbt2   = "bmbt2"
+		fieldIbt2    = "ibt2"
+		fieldFibt2   = "fibt2"
+		fieldQm      = "qm"
+		fieldDebug   = "debug"
+	)
+
+	var xfss Stats
+
+	s := bufio.NewScanner(r)
+	for s.Scan() {
+		// Expect at least a string label and a single integer value, ex:
+		//   - abt 0
+		//   - rw 1 2
+		ss := strings.Fields(string(s.Bytes()))
+		if len(ss) < 2 {
+			continue
+		}
+		label := ss[0]
+
+		// Extended precision counters are uint64 values.
+		if label == fieldXpc {
+			us, err := util.ParseUint64s(ss[1:])
+			if err != nil {
+				return nil, err
+			}
+
+			xfss.ExtendedPrecision, err = extendedPrecisionStats(us)
+			if err != nil {
+				return nil, err
+			}
+
+			continue
+		}
+
+		// All other counters are uint32 values.
+		us, err := util.ParseUint32s(ss[1:])
+		if err != nil {
+			return nil, err
+		}
+
+		switch label {
+		case fieldExtentAlloc:
+			xfss.ExtentAllocation, err = extentAllocationStats(us)
+		case fieldAbt:
+			xfss.AllocationBTree, err = btreeStats(us)
+		case fieldBlkMap:
+			xfss.BlockMapping, err = blockMappingStats(us)
+		case fieldBmbt:
+			xfss.BlockMapBTree, err = btreeStats(us)
+		case fieldDir:
+			xfss.DirectoryOperation, err = directoryOperationStats(us)
+		case fieldTrans:
+			xfss.Transaction, err = transactionStats(us)
+		case fieldIg:
+			xfss.InodeOperation, err = inodeOperationStats(us)
+		case fieldLog:
+			xfss.LogOperation, err = logOperationStats(us)
+		case fieldRw:
+			xfss.ReadWrite, err = readWriteStats(us)
+		case fieldAttr:
+			xfss.AttributeOperation, err = attributeOperationStats(us)
+		case fieldIcluster:
+			xfss.InodeClustering, err = inodeClusteringStats(us)
+		case fieldVnodes:
+			xfss.Vnode, err = vnodeStats(us)
+		case fieldBuf:
+			xfss.Buffer, err = bufferStats(us)
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return &xfss, s.Err()
+}
+
+// extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s.
+func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) {
+	if l := len(us); l != 4 {
+		return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l)
+	}
+
+	return ExtentAllocationStats{
+		ExtentsAllocated: us[0],
+		BlocksAllocated:  us[1],
+		ExtentsFreed:     us[2],
+		BlocksFreed:      us[3],
+	}, nil
+}
+
+// btreeStats builds a BTreeStats from a slice of uint32s.
+func btreeStats(us []uint32) (BTreeStats, error) {
+	if l := len(us); l != 4 {
+		return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l)
+	}
+
+	return BTreeStats{
+		Lookups:         us[0],
+		Compares:        us[1],
+		RecordsInserted: us[2],
+		RecordsDeleted:  us[3],
+	}, nil
+}
+
+// BlockMappingStat builds a BlockMappingStats from a slice of uint32s.
+func blockMappingStats(us []uint32) (BlockMappingStats, error) {
+	if l := len(us); l != 7 {
+		return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l)
+	}
+
+	return BlockMappingStats{
+		Reads:                us[0],
+		Writes:               us[1],
+		Unmaps:               us[2],
+		ExtentListInsertions: us[3],
+		ExtentListDeletions:  us[4],
+		ExtentListLookups:    us[5],
+		ExtentListCompares:   us[6],
+	}, nil
+}
+
+// DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s.
+func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) {
+	if l := len(us); l != 4 {
+		return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l)
+	}
+
+	return DirectoryOperationStats{
+		Lookups:  us[0],
+		Creates:  us[1],
+		Removes:  us[2],
+		Getdents: us[3],
+	}, nil
+}
+
+// TransactionStats builds a TransactionStats from a slice of uint32s.
+func transactionStats(us []uint32) (TransactionStats, error) {
+	if l := len(us); l != 3 {
+		return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l)
+	}
+
+	return TransactionStats{
+		Sync:  us[0],
+		Async: us[1],
+		Empty: us[2],
+	}, nil
+}
+
+// InodeOperationStats builds an InodeOperationStats from a slice of uint32s.
+func inodeOperationStats(us []uint32) (InodeOperationStats, error) {
+	if l := len(us); l != 7 {
+		return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l)
+	}
+
+	return InodeOperationStats{
+		Attempts:        us[0],
+		Found:           us[1],
+		Recycle:         us[2],
+		Missed:          us[3],
+		Duplicate:       us[4],
+		Reclaims:        us[5],
+		AttributeChange: us[6],
+	}, nil
+}
+
+// LogOperationStats builds a LogOperationStats from a slice of uint32s.
+func logOperationStats(us []uint32) (LogOperationStats, error) {
+	if l := len(us); l != 5 {
+		return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l)
+	}
+
+	return LogOperationStats{
+		Writes:            us[0],
+		Blocks:            us[1],
+		NoInternalBuffers: us[2],
+		Force:             us[3],
+		ForceSleep:        us[4],
+	}, nil
+}
+
+// ReadWriteStats builds a ReadWriteStats from a slice of uint32s.
+func readWriteStats(us []uint32) (ReadWriteStats, error) {
+	if l := len(us); l != 2 {
+		return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l)
+	}
+
+	return ReadWriteStats{
+		Read:  us[0],
+		Write: us[1],
+	}, nil
+}
+
+// AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s.
+func attributeOperationStats(us []uint32) (AttributeOperationStats, error) {
+	if l := len(us); l != 4 {
+		return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l)
+	}
+
+	return AttributeOperationStats{
+		Get:    us[0],
+		Set:    us[1],
+		Remove: us[2],
+		List:   us[3],
+	}, nil
+}
+
+// InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s.
+func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) {
+	if l := len(us); l != 3 {
+		return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l)
+	}
+
+	return InodeClusteringStats{
+		Iflush:     us[0],
+		Flush:      us[1],
+		FlushInode: us[2],
+	}, nil
+}
+
+// VnodeStats builds a VnodeStats from a slice of uint32s.
+func vnodeStats(us []uint32) (VnodeStats, error) {
+	// The attribute "Free" appears to not be available on older XFS
+	// stats versions.  Therefore, 7 or 8 elements may appear in
+	// this slice.
+	l := len(us)
+	if l != 7 && l != 8 {
+		return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l)
+	}
+
+	s := VnodeStats{
+		Active:   us[0],
+		Allocate: us[1],
+		Get:      us[2],
+		Hold:     us[3],
+		Release:  us[4],
+		Reclaim:  us[5],
+		Remove:   us[6],
+	}
+
+	// Skip adding free, unless it is present. The zero value will
+	// be used in place of an actual count.
+	if l == 7 {
+		return s, nil
+	}
+
+	s.Free = us[7]
+	return s, nil
+}
+
+// BufferStats builds a BufferStats from a slice of uint32s.
+func bufferStats(us []uint32) (BufferStats, error) {
+	if l := len(us); l != 9 {
+		return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l)
+	}
+
+	return BufferStats{
+		Get:             us[0],
+		Create:          us[1],
+		GetLocked:       us[2],
+		GetLockedWaited: us[3],
+		BusyLocked:      us[4],
+		MissLocked:      us[5],
+		PageRetries:     us[6],
+		PageFound:       us[7],
+		GetRead:         us[8],
+	}, nil
+}
+
+// ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s.
+func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) {
+	if l := len(us); l != 3 {
+		return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l)
+	}
+
+	return ExtendedPrecisionStats{
+		FlushBytes: us[0],
+		WriteBytes: us[1],
+		ReadBytes:  us[2],
+	}, nil
+}

+ 163 - 0
vendor/github.com/prometheus/procfs/xfs/xfs.go

@@ -0,0 +1,163 @@
+// Copyright 2017 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 xfs provides access to statistics exposed by the XFS filesystem.
+package xfs
+
+// Stats contains XFS filesystem runtime statistics, parsed from
+// /proc/fs/xfs/stat.
+//
+// The names and meanings of each statistic were taken from
+// http://xfs.org/index.php/Runtime_Stats and xfs_stats.h in the Linux
+// kernel source. Most counters are uint32s (same data types used in
+// xfs_stats.h), but some of the "extended precision stats" are uint64s.
+type Stats struct {
+	// The name of the filesystem used to source these statistics.
+	// If empty, this indicates aggregated statistics for all XFS
+	// filesystems on the host.
+	Name string
+
+	ExtentAllocation   ExtentAllocationStats
+	AllocationBTree    BTreeStats
+	BlockMapping       BlockMappingStats
+	BlockMapBTree      BTreeStats
+	DirectoryOperation DirectoryOperationStats
+	Transaction        TransactionStats
+	InodeOperation     InodeOperationStats
+	LogOperation       LogOperationStats
+	ReadWrite          ReadWriteStats
+	AttributeOperation AttributeOperationStats
+	InodeClustering    InodeClusteringStats
+	Vnode              VnodeStats
+	Buffer             BufferStats
+	ExtendedPrecision  ExtendedPrecisionStats
+}
+
+// ExtentAllocationStats contains statistics regarding XFS extent allocations.
+type ExtentAllocationStats struct {
+	ExtentsAllocated uint32
+	BlocksAllocated  uint32
+	ExtentsFreed     uint32
+	BlocksFreed      uint32
+}
+
+// BTreeStats contains statistics regarding an XFS internal B-tree.
+type BTreeStats struct {
+	Lookups         uint32
+	Compares        uint32
+	RecordsInserted uint32
+	RecordsDeleted  uint32
+}
+
+// BlockMappingStats contains statistics regarding XFS block maps.
+type BlockMappingStats struct {
+	Reads                uint32
+	Writes               uint32
+	Unmaps               uint32
+	ExtentListInsertions uint32
+	ExtentListDeletions  uint32
+	ExtentListLookups    uint32
+	ExtentListCompares   uint32
+}
+
+// DirectoryOperationStats contains statistics regarding XFS directory entries.
+type DirectoryOperationStats struct {
+	Lookups  uint32
+	Creates  uint32
+	Removes  uint32
+	Getdents uint32
+}
+
+// TransactionStats contains statistics regarding XFS metadata transactions.
+type TransactionStats struct {
+	Sync  uint32
+	Async uint32
+	Empty uint32
+}
+
+// InodeOperationStats contains statistics regarding XFS inode operations.
+type InodeOperationStats struct {
+	Attempts        uint32
+	Found           uint32
+	Recycle         uint32
+	Missed          uint32
+	Duplicate       uint32
+	Reclaims        uint32
+	AttributeChange uint32
+}
+
+// LogOperationStats contains statistics regarding the XFS log buffer.
+type LogOperationStats struct {
+	Writes            uint32
+	Blocks            uint32
+	NoInternalBuffers uint32
+	Force             uint32
+	ForceSleep        uint32
+}
+
+// ReadWriteStats contains statistics regarding the number of read and write
+// system calls for XFS filesystems.
+type ReadWriteStats struct {
+	Read  uint32
+	Write uint32
+}
+
+// AttributeOperationStats contains statistics regarding manipulation of
+// XFS extended file attributes.
+type AttributeOperationStats struct {
+	Get    uint32
+	Set    uint32
+	Remove uint32
+	List   uint32
+}
+
+// InodeClusteringStats contains statistics regarding XFS inode clustering
+// operations.
+type InodeClusteringStats struct {
+	Iflush     uint32
+	Flush      uint32
+	FlushInode uint32
+}
+
+// VnodeStats contains statistics regarding XFS vnode operations.
+type VnodeStats struct {
+	Active   uint32
+	Allocate uint32
+	Get      uint32
+	Hold     uint32
+	Release  uint32
+	Reclaim  uint32
+	Remove   uint32
+	Free     uint32
+}
+
+// BufferStats contains statistics regarding XFS read/write I/O buffers.
+type BufferStats struct {
+	Get             uint32
+	Create          uint32
+	GetLocked       uint32
+	GetLockedWaited uint32
+	BusyLocked      uint32
+	MissLocked      uint32
+	PageRetries     uint32
+	PageFound       uint32
+	GetRead         uint32
+}
+
+// ExtendedPrecisionStats contains high precision counters used to track the
+// total number of bytes read, written, or flushed, during XFS operations.
+type ExtendedPrecisionStats struct {
+	FlushBytes uint64
+	WriteBytes uint64
+	ReadBytes  uint64
+}

部分文件因文件數量過多而無法顯示