diff --git a/CHANGELOG.md b/CHANGELOG.md index 86d380ad..28cefae4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,15 @@ ### **Breaking changes** +The cpufreq metrics now separate the `cpufreq` and `scaling` data based on what the driver provides. #1248 + ### Changes * [BUGFIX] * [BUGFIX] Add fallback for missing /proc/1/mounts #1172 * [CHANGE] Add TCPSynRetrans to netstat default filter #1143 * [CHANGE] Add a limit to the number of in-flight requests #1166 +* [CHANGE] Add separate cpufreq and scaling metrics #1248 * [ENHANCEMENT] Add Infiniband counters #1120 * [FEATURE] Add a flag to disable exporter metrics #1148 * [FEATURE] Add kstat-based Solaris metrics for boottime, cpu and zfs collectors #1197 diff --git a/collector/cpu_linux.go b/collector/cpu_linux.go index 640873f4..50d8a3b1 100644 --- a/collector/cpu_linux.go +++ b/collector/cpu_linux.go @@ -32,6 +32,9 @@ type cpuCollector struct { cpuFreq *prometheus.Desc cpuFreqMin *prometheus.Desc cpuFreqMax *prometheus.Desc + scalingFreq *prometheus.Desc + scalingFreqMin *prometheus.Desc + scalingFreqMax *prometheus.Desc cpuCoreThrottle *prometheus.Desc cpuPackageThrottle *prometheus.Desc } @@ -64,6 +67,21 @@ func NewCPUCollector() (Collector, error) { "Maximum cpu thread frequency in hertz.", []string{"cpu"}, nil, ), + scalingFreq: prometheus.NewDesc( + prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "scaling_frequency_hertz"), + "Current scaled cpu thread frequency in hertz.", + []string{"cpu"}, nil, + ), + scalingFreqMin: prometheus.NewDesc( + prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "scaling_frequency_min_hrts"), + "Minimum scaled cpu thread frequency in hertz.", + []string{"cpu"}, nil, + ), + scalingFreqMax: prometheus.NewDesc( + prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "scaling_frequency_max_hrts"), + "Maximum scaled cpu thread frequency in hertz.", + []string{"cpu"}, nil, + ), cpuCoreThrottle: prometheus.NewDesc( prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "core_throttles_total"), "Number of times this cpu core has been throttled.", @@ -106,24 +124,54 @@ func (c *cpuCollector) updateCPUfreq(ch chan<- prometheus.Metric) error { // sysfs cpufreq values are kHz, thus multiply by 1000 to export base units (hz). // See https://www.kernel.org/doc/Documentation/cpu-freq/user-guide.txt for _, stats := range cpuFreqs { - ch <- prometheus.MustNewConstMetric( - c.cpuFreq, - prometheus.GaugeValue, - float64(stats.CurrentFrequency)*1000.0, - stats.Name, - ) - ch <- prometheus.MustNewConstMetric( - c.cpuFreqMin, - prometheus.GaugeValue, - float64(stats.MinimumFrequency)*1000.0, - stats.Name, - ) - ch <- prometheus.MustNewConstMetric( - c.cpuFreqMax, - prometheus.GaugeValue, - float64(stats.MaximumFrequency)*1000.0, - stats.Name, - ) + if stats.CpuinfoCurrentFrequency != nil { + ch <- prometheus.MustNewConstMetric( + c.cpuFreq, + prometheus.GaugeValue, + float64(*stats.CpuinfoCurrentFrequency)*1000.0, + stats.Name, + ) + } + if stats.CpuinfoMinimumFrequency != nil { + ch <- prometheus.MustNewConstMetric( + c.cpuFreqMin, + prometheus.GaugeValue, + float64(*stats.CpuinfoMinimumFrequency)*1000.0, + stats.Name, + ) + } + if stats.CpuinfoMaximumFrequency != nil { + ch <- prometheus.MustNewConstMetric( + c.cpuFreqMax, + prometheus.GaugeValue, + float64(*stats.CpuinfoMaximumFrequency)*1000.0, + stats.Name, + ) + } + if stats.ScalingCurrentFrequency != nil { + ch <- prometheus.MustNewConstMetric( + c.scalingFreq, + prometheus.GaugeValue, + float64(*stats.ScalingCurrentFrequency)*1000.0, + stats.Name, + ) + } + if stats.ScalingMinimumFrequency != nil { + ch <- prometheus.MustNewConstMetric( + c.scalingFreqMin, + prometheus.GaugeValue, + float64(*stats.ScalingMinimumFrequency)*1000.0, + stats.Name, + ) + } + if stats.ScalingMaximumFrequency != nil { + ch <- prometheus.MustNewConstMetric( + c.scalingFreqMax, + prometheus.GaugeValue, + float64(*stats.ScalingMaximumFrequency)*1000.0, + stats.Name, + ) + } } return nil } diff --git a/collector/fixtures/e2e-64k-page-output.txt b/collector/fixtures/e2e-64k-page-output.txt index feb6b37b..7e61462e 100644 --- a/collector/fixtures/e2e-64k-page-output.txt +++ b/collector/fixtures/e2e-64k-page-output.txt @@ -184,24 +184,6 @@ node_cpu_core_throttles_total{core="0",package="0"} 5 node_cpu_core_throttles_total{core="0",package="1"} 0 node_cpu_core_throttles_total{core="1",package="0"} 0 node_cpu_core_throttles_total{core="1",package="1"} 9 -# HELP node_cpu_frequency_hertz Current cpu thread frequency in hertz. -# TYPE node_cpu_frequency_hertz gauge -node_cpu_frequency_hertz{cpu="0"} 1.699981e+09 -node_cpu_frequency_hertz{cpu="1"} 1.699981e+09 -node_cpu_frequency_hertz{cpu="2"} 8e+06 -node_cpu_frequency_hertz{cpu="3"} 8e+06 -# HELP node_cpu_frequency_max_hertz Maximum cpu thread frequency in hertz. -# TYPE node_cpu_frequency_max_hertz gauge -node_cpu_frequency_max_hertz{cpu="0"} 3.7e+09 -node_cpu_frequency_max_hertz{cpu="1"} 3.7e+09 -node_cpu_frequency_max_hertz{cpu="2"} 4.2e+09 -node_cpu_frequency_max_hertz{cpu="3"} 4.2e+09 -# HELP node_cpu_frequency_min_hertz Minimum cpu thread frequency in hertz. -# TYPE node_cpu_frequency_min_hertz gauge -node_cpu_frequency_min_hertz{cpu="0"} 8e+08 -node_cpu_frequency_min_hertz{cpu="1"} 8e+08 -node_cpu_frequency_min_hertz{cpu="2"} 1e+06 -node_cpu_frequency_min_hertz{cpu="3"} 1e+06 # HELP node_cpu_guest_seconds_total Seconds the cpus spent in guests (VMs) for each mode. # TYPE node_cpu_guest_seconds_total counter node_cpu_guest_seconds_total{cpu="0",mode="nice"} 0.01 @@ -224,6 +206,24 @@ node_cpu_guest_seconds_total{cpu="7",mode="user"} 0.09 # TYPE node_cpu_package_throttles_total counter node_cpu_package_throttles_total{package="0"} 30 node_cpu_package_throttles_total{package="1"} 6 +# HELP node_cpu_scaling_frequency_hertz Current scaled cpu thread frequency in hertz. +# TYPE node_cpu_scaling_frequency_hertz gauge +node_cpu_scaling_frequency_hertz{cpu="0"} 1.699981e+09 +node_cpu_scaling_frequency_hertz{cpu="1"} 1.699981e+09 +node_cpu_scaling_frequency_hertz{cpu="2"} 8e+06 +node_cpu_scaling_frequency_hertz{cpu="3"} 8e+06 +# HELP node_cpu_scaling_frequency_max_hrts Maximum scaled cpu thread frequency in hertz. +# TYPE node_cpu_scaling_frequency_max_hrts gauge +node_cpu_scaling_frequency_max_hrts{cpu="0"} 3.7e+09 +node_cpu_scaling_frequency_max_hrts{cpu="1"} 3.7e+09 +node_cpu_scaling_frequency_max_hrts{cpu="2"} 4.2e+09 +node_cpu_scaling_frequency_max_hrts{cpu="3"} 4.2e+09 +# HELP node_cpu_scaling_frequency_min_hrts Minimum scaled cpu thread frequency in hertz. +# TYPE node_cpu_scaling_frequency_min_hrts gauge +node_cpu_scaling_frequency_min_hrts{cpu="0"} 8e+08 +node_cpu_scaling_frequency_min_hrts{cpu="1"} 8e+08 +node_cpu_scaling_frequency_min_hrts{cpu="2"} 1e+06 +node_cpu_scaling_frequency_min_hrts{cpu="3"} 1e+06 # HELP node_cpu_seconds_total Seconds the cpus spent in each mode. # TYPE node_cpu_seconds_total counter node_cpu_seconds_total{cpu="0",mode="idle"} 10870.69 diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index 588a5873..ba11e234 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -184,24 +184,6 @@ node_cpu_core_throttles_total{core="0",package="0"} 5 node_cpu_core_throttles_total{core="0",package="1"} 0 node_cpu_core_throttles_total{core="1",package="0"} 0 node_cpu_core_throttles_total{core="1",package="1"} 9 -# HELP node_cpu_frequency_hertz Current cpu thread frequency in hertz. -# TYPE node_cpu_frequency_hertz gauge -node_cpu_frequency_hertz{cpu="0"} 1.699981e+09 -node_cpu_frequency_hertz{cpu="1"} 1.699981e+09 -node_cpu_frequency_hertz{cpu="2"} 8e+06 -node_cpu_frequency_hertz{cpu="3"} 8e+06 -# HELP node_cpu_frequency_max_hertz Maximum cpu thread frequency in hertz. -# TYPE node_cpu_frequency_max_hertz gauge -node_cpu_frequency_max_hertz{cpu="0"} 3.7e+09 -node_cpu_frequency_max_hertz{cpu="1"} 3.7e+09 -node_cpu_frequency_max_hertz{cpu="2"} 4.2e+09 -node_cpu_frequency_max_hertz{cpu="3"} 4.2e+09 -# HELP node_cpu_frequency_min_hertz Minimum cpu thread frequency in hertz. -# TYPE node_cpu_frequency_min_hertz gauge -node_cpu_frequency_min_hertz{cpu="0"} 8e+08 -node_cpu_frequency_min_hertz{cpu="1"} 8e+08 -node_cpu_frequency_min_hertz{cpu="2"} 1e+06 -node_cpu_frequency_min_hertz{cpu="3"} 1e+06 # HELP node_cpu_guest_seconds_total Seconds the cpus spent in guests (VMs) for each mode. # TYPE node_cpu_guest_seconds_total counter node_cpu_guest_seconds_total{cpu="0",mode="nice"} 0.01 @@ -224,6 +206,24 @@ node_cpu_guest_seconds_total{cpu="7",mode="user"} 0.09 # TYPE node_cpu_package_throttles_total counter node_cpu_package_throttles_total{package="0"} 30 node_cpu_package_throttles_total{package="1"} 6 +# HELP node_cpu_scaling_frequency_hertz Current scaled cpu thread frequency in hertz. +# TYPE node_cpu_scaling_frequency_hertz gauge +node_cpu_scaling_frequency_hertz{cpu="0"} 1.699981e+09 +node_cpu_scaling_frequency_hertz{cpu="1"} 1.699981e+09 +node_cpu_scaling_frequency_hertz{cpu="2"} 8e+06 +node_cpu_scaling_frequency_hertz{cpu="3"} 8e+06 +# HELP node_cpu_scaling_frequency_max_hrts Maximum scaled cpu thread frequency in hertz. +# TYPE node_cpu_scaling_frequency_max_hrts gauge +node_cpu_scaling_frequency_max_hrts{cpu="0"} 3.7e+09 +node_cpu_scaling_frequency_max_hrts{cpu="1"} 3.7e+09 +node_cpu_scaling_frequency_max_hrts{cpu="2"} 4.2e+09 +node_cpu_scaling_frequency_max_hrts{cpu="3"} 4.2e+09 +# HELP node_cpu_scaling_frequency_min_hrts Minimum scaled cpu thread frequency in hertz. +# TYPE node_cpu_scaling_frequency_min_hrts gauge +node_cpu_scaling_frequency_min_hrts{cpu="0"} 8e+08 +node_cpu_scaling_frequency_min_hrts{cpu="1"} 8e+08 +node_cpu_scaling_frequency_min_hrts{cpu="2"} 1e+06 +node_cpu_scaling_frequency_min_hrts{cpu="3"} 1e+06 # HELP node_cpu_seconds_total Seconds the cpus spent in each mode. # TYPE node_cpu_seconds_total counter node_cpu_seconds_total{cpu="0",mode="idle"} 10870.69 diff --git a/go.mod b/go.mod index 8b80a617..c6ea6a6e 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/prometheus/client_golang v0.9.1 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37 - github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d + github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5 github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 github.com/sirupsen/logrus v1.1.1 // indirect github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a diff --git a/go.sum b/go.sum index 8fec81b2..235249cf 100644 --- a/go.sum +++ b/go.sum @@ -43,8 +43,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37 h1:Y7YdJ9Xb3MoQOzAWXnDunAJYpvhVwZdTirNfGUgPKaA= github.com/prometheus/common v0.0.0-20181015124227-bcb74de08d37/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5 h1:Etei0Wx6pooT/DeOKcGTr1M/01ggz95Ajq8BBwCOKBU= +github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 h1:IuH7WumZNax0D+rEqmy2TyhKCzrtMGqbZO0b8rO00JA= github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8= github.com/sirupsen/logrus v1.1.1 h1:VzGj7lhU7KEB9e9gMpAV/v5XT2NVSvLJhJLCWbnkgXg= diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md index 35993c41..f1d3b993 100644 --- a/vendor/github.com/prometheus/procfs/MAINTAINERS.md +++ b/vendor/github.com/prometheus/procfs/MAINTAINERS.md @@ -1 +1,2 @@ -* Tobias Schmidt +* Tobias Schmidt @grobie +* Johannes 'fish' Ziemke @discordianfish diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile index 4d109839..947d7d8f 100644 --- a/vendor/github.com/prometheus/procfs/Makefile +++ b/vendor/github.com/prometheus/procfs/Makefile @@ -11,49 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Ensure GOBIN is not set during build so that promu is installed to the correct path -unexport GOBIN - -GO ?= go -GOFMT ?= $(GO)fmt -FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) -STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck -pkgs = $(shell $(GO) list ./... | grep -v /vendor/) - -PREFIX ?= $(shell pwd) -BIN_DIR ?= $(shell pwd) - -ifdef DEBUG - bindata_flags = -debug -endif - -STATICCHECK_IGNORE = - -all: format staticcheck build test - -style: - @echo ">> checking code style" - @! $(GOFMT) -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^' - -check_license: - @echo ">> checking license header" - @./scripts/check_license.sh - -test: fixtures/.unpacked sysfs/fixtures/.unpacked - @echo ">> running all tests" - @$(GO) test -race $(shell $(GO) list ./... | grep -v /vendor/ | grep -v examples) - -format: - @echo ">> formatting code" - @$(GO) fmt $(pkgs) - -vet: - @echo ">> vetting code" - @$(GO) vet $(pkgs) - -staticcheck: $(STATICCHECK) - @echo ">> running staticcheck" - @$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) +include Makefile.common %/.unpacked: %.ttar ./ttar -C $(dir $*) -x -f $*.ttar @@ -65,13 +23,8 @@ update_fixtures: fixtures.ttar sysfs/fixtures.ttar rm -v $(dir $*)fixtures/.unpacked ./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/ -$(FIRST_GOPATH)/bin/staticcheck: - @GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck +.PHONY: build +build: -.PHONY: all style check_license format test vet staticcheck - -# Declaring the binaries at their default locations as PHONY targets is a hack -# to ensure the latest version is downloaded on every make execution. -# If this is not desired, copy/symlink these binaries to a different path and -# set the respective environment variables. -.PHONY: $(GOPATH)/bin/staticcheck +.PHONY: test +test: fixtures/.unpacked sysfs/fixtures/.unpacked common-test diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common new file mode 100644 index 00000000..741579e6 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/Makefile.common @@ -0,0 +1,223 @@ +# 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. + + +# A common Makefile that includes rules to be reused in different prometheus projects. +# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository! + +# Example usage : +# Create the main Makefile in the root project directory. +# include Makefile.common +# customTarget: +# @echo ">> Running customTarget" +# + +# Ensure GOBIN is not set during build so that promu is installed to the correct path +unexport GOBIN + +GO ?= go +GOFMT ?= $(GO)fmt +FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) +GOOPTS ?= + +GO_VERSION ?= $(shell $(GO) version) +GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) +PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') + +unexport GOVENDOR +ifeq (, $(PRE_GO_111)) + ifneq (,$(wildcard go.mod)) + # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). + GO111MODULE := on + + ifneq (,$(wildcard vendor)) + # Always use the local vendor/ directory to satisfy the dependencies. + GOOPTS := $(GOOPTS) -mod=vendor + endif + endif +else + ifneq (,$(wildcard go.mod)) + ifneq (,$(wildcard vendor)) +$(warning This repository requires Go >= 1.11 because of Go modules) +$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') + endif + else + # This repository isn't using Go modules (yet). + GOVENDOR := $(FIRST_GOPATH)/bin/govendor + endif + + unexport GO111MODULE +endif +PROMU := $(FIRST_GOPATH)/bin/promu +STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck +pkgs = ./... + +GO_VERSION ?= $(shell $(GO) version) +GO_BUILD_PLATFORM ?= $(subst /,-,$(lastword $(GO_VERSION))) + +PROMU_VERSION ?= 0.2.0 +PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz + +PREFIX ?= $(shell pwd) +BIN_DIR ?= $(shell pwd) +DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) +DOCKER_REPO ?= prom + +.PHONY: all +all: precheck style staticcheck unused build test + +# This rule is used to forward a target like "build" to "common-build". This +# allows a new "build" target to be defined in a Makefile which includes this +# one and override "common-build" without override warnings. +%: common-% ; + +.PHONY: common-style +common-style: + @echo ">> checking code style" + @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ + if [ -n "$${fmtRes}" ]; then \ + echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ + echo "Please ensure you are using $$($(GO) version) for formatting code."; \ + exit 1; \ + fi + +.PHONY: common-check_license +common-check_license: + @echo ">> checking license header" + @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \ + awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \ + done); \ + if [ -n "$${licRes}" ]; then \ + echo "license header checking failed:"; echo "$${licRes}"; \ + exit 1; \ + fi + +.PHONY: common-test-short +common-test-short: + @echo ">> running short tests" + GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs) + +.PHONY: common-test +common-test: + @echo ">> running all tests" + GO111MODULE=$(GO111MODULE) $(GO) test -race $(GOOPTS) $(pkgs) + +.PHONY: common-format +common-format: + @echo ">> formatting code" + GO111MODULE=$(GO111MODULE) $(GO) fmt $(GOOPTS) $(pkgs) + +.PHONY: common-vet +common-vet: + @echo ">> vetting code" + GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) + +.PHONY: common-staticcheck +common-staticcheck: $(STATICCHECK) + @echo ">> running staticcheck" +ifdef GO111MODULE + GO111MODULE=$(GO111MODULE) $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" -checks "SA*" $(pkgs) +else + $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) +endif + +.PHONY: common-unused +common-unused: $(GOVENDOR) +ifdef GOVENDOR + @echo ">> running check for unused packages" + @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' +else +ifdef GO111MODULE + @echo ">> running check for unused/missing packages in go.mod" + GO111MODULE=$(GO111MODULE) $(GO) mod tidy + @git diff --exit-code -- go.sum go.mod +ifneq (,$(wildcard vendor)) + @echo ">> running check for unused packages in vendor/" + GO111MODULE=$(GO111MODULE) $(GO) mod vendor + @git diff --exit-code -- go.sum go.mod vendor/ +endif +endif +endif + +.PHONY: common-build +common-build: promu + @echo ">> building binaries" + GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) + +.PHONY: common-tarball +common-tarball: promu + @echo ">> building release tarball" + $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) + +.PHONY: common-docker +common-docker: + docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" . + +.PHONY: common-docker-publish +common-docker-publish: + docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" + +.PHONY: common-docker-tag-latest +common-docker-tag-latest: + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):latest" + +.PHONY: promu +promu: $(PROMU) + +$(PROMU): + curl -s -L $(PROMU_URL) | tar -xvz -C /tmp + mkdir -v -p $(FIRST_GOPATH)/bin + cp -v /tmp/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(PROMU) + +.PHONY: proto +proto: + @echo ">> generating code from proto files" + @./scripts/genproto.sh + +.PHONY: $(STATICCHECK) +$(STATICCHECK): +ifdef GO111MODULE +# Get staticcheck from a temporary directory to avoid modifying the local go.{mod,sum}. +# See https://github.com/golang/go/issues/27643. +# For now, we are using the next branch of staticcheck because master isn't compatible yet with Go modules. + tmpModule=$$(mktemp -d 2>&1) && \ + mkdir -p $${tmpModule}/staticcheck && \ + cd "$${tmpModule}"/staticcheck && \ + GO111MODULE=on $(GO) mod init example.com/staticcheck && \ + GO111MODULE=on GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck@next && \ + rm -rf $${tmpModule}; +else + GOOS= GOARCH= GO111MODULE=off $(GO) get -u honnef.co/go/tools/cmd/staticcheck +endif + +ifdef GOVENDOR +.PHONY: $(GOVENDOR) +$(GOVENDOR): + GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor +endif + +.PHONY: precheck +precheck:: + +define PRECHECK_COMMAND_template = +precheck:: $(1)_precheck + + +PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) +.PHONY: $(1)_precheck +$(1)_precheck: + @if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \ + echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \ + exit 1; \ + fi +endef diff --git a/vendor/github.com/prometheus/procfs/go.mod b/vendor/github.com/prometheus/procfs/go.mod new file mode 100644 index 00000000..e89ee6c9 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/go.mod @@ -0,0 +1 @@ +module github.com/prometheus/procfs diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/util/parse.go index 2ff228e9..ca74889a 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/parse.go +++ b/vendor/github.com/prometheus/procfs/internal/util/parse.go @@ -57,3 +57,17 @@ func ReadUintFromFile(path string) (uint64, error) { } return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) } + +// ParseBool parses a string into a boolean pointer. +func ParseBool(b string) *bool { + var truth bool + switch b { + case "enabled": + truth = true + case "disabled": + truth = false + default: + return nil + } + return &truth +} diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go index 7a8a1e09..fc385afc 100644 --- a/vendor/github.com/prometheus/procfs/mountstats.go +++ b/vendor/github.com/prometheus/procfs/mountstats.go @@ -69,6 +69,8 @@ type MountStats interface { type MountStatsNFS struct { // The version of statistics provided. StatVersion string + // The optional mountaddr of the NFS mount. + MountAddress string // The age of the NFS mount. Age time.Duration // Statistics related to byte counters for various operations. @@ -317,6 +319,7 @@ func parseMount(ss []string) (*Mount, error) { func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) { // Field indicators for parsing specific types of data const ( + fieldOpts = "opts:" fieldAge = "age:" fieldBytes = "bytes:" fieldEvents = "events:" @@ -338,6 +341,13 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e } switch ss[0] { + case fieldOpts: + for _, opt := range strings.Split(ss[1], ",") { + split := strings.Split(opt, "=") + if len(split) == 2 && split[0] == "mountaddr" { + stats.MountAddress = split[1] + } + } case fieldAge: // Age integer is in seconds d, err := time.ParseDuration(ss[1] + "s") diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go index 3cf2a9f1..e7c626a8 100644 --- a/vendor/github.com/prometheus/procfs/proc_stat.go +++ b/vendor/github.com/prometheus/procfs/proc_stat.go @@ -95,7 +95,7 @@ type ProcStat struct { // in clock ticks. Starttime uint64 // Virtual memory size in bytes. - VSize int + VSize uint // Resident set size in pages. RSS int @@ -164,7 +164,7 @@ func (p Proc) NewStat() (ProcStat, error) { } // VirtualMemory returns the virtual memory size in bytes. -func (s ProcStat) VirtualMemory() int { +func (s ProcStat) VirtualMemory() uint { return s.VSize } diff --git a/vendor/github.com/prometheus/procfs/sysfs/class_thermal.go b/vendor/github.com/prometheus/procfs/sysfs/class_thermal.go new file mode 100644 index 00000000..4f9cb9a1 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/sysfs/class_thermal.go @@ -0,0 +1,99 @@ +// 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. + +// +build !windows + +package sysfs + +import ( + "os" + "path/filepath" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// ClassThermalZoneStats contains info from files in /sys/class/thermal/thermal_zone +// for a single . +// https://www.kernel.org/doc/Documentation/thermal/sysfs-api.txt +type ClassThermalZoneStats struct { + Name string // The name of the zone from the directory structure. + Type string // The type of thermal zone. + Temp uint64 // Temperature in millidegree Celsius. + Policy string // One of the various thermal governors used for a particular zone. + Mode *bool // Optional: One of the predefined values in [enabled, disabled]. + Passive *uint64 // Optional: millidegrees Celsius. (0 for disabled, > 1000 for enabled+value) +} + +// NewClassThermalZoneStats returns Thermal Zone metrics for all zones. +func (fs FS) NewClassThermalZoneStats() ([]ClassThermalZoneStats, error) { + zones, err := filepath.Glob(fs.Path("class/thermal/thermal_zone[0-9]*")) + if err != nil { + return []ClassThermalZoneStats{}, err + } + + var zoneStats = ClassThermalZoneStats{} + stats := make([]ClassThermalZoneStats, len(zones)) + for i, zone := range zones { + zoneName := strings.TrimPrefix(filepath.Base(zone), "thermal_zone") + + zoneStats, err = parseClassThermalZone(zone) + if err != nil { + return []ClassThermalZoneStats{}, err + } + zoneStats.Name = zoneName + stats[i] = zoneStats + } + return stats, nil +} + +func parseClassThermalZone(zone string) (ClassThermalZoneStats, error) { + // Required attributes. + zoneType, err := util.SysReadFile(filepath.Join(zone, "type")) + if err != nil { + return ClassThermalZoneStats{}, err + } + zonePolicy, err := util.SysReadFile(filepath.Join(zone, "policy")) + if err != nil { + return ClassThermalZoneStats{}, err + } + zoneTemp, err := util.ReadUintFromFile(filepath.Join(zone, "temp")) + if err != nil { + return ClassThermalZoneStats{}, err + } + + // Optional attributes. + mode, err := util.SysReadFile(filepath.Join(zone, "mode")) + if err != nil && !os.IsNotExist(err) && !os.IsPermission(err) { + return ClassThermalZoneStats{}, err + } + zoneMode := util.ParseBool(mode) + + var zonePassive *uint64 + passive, err := util.ReadUintFromFile(filepath.Join(zone, "passive")) + if os.IsNotExist(err) || os.IsPermission(err) { + zonePassive = nil + } else if err != nil { + return ClassThermalZoneStats{}, err + } else { + zonePassive = &passive + } + + return ClassThermalZoneStats{ + Type: zoneType, + Policy: zonePolicy, + Temp: zoneTemp, + Mode: zoneMode, + Passive: zonePassive, + }, nil +} diff --git a/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar b/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar index c0ac683e..33bdbdb8 100644 --- a/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar +++ b/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar @@ -137,6 +137,55 @@ Lines: 1 1 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/class/thermal +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/class/thermal/thermal_zone0 +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/class/thermal/thermal_zone0/policy +Lines: 1 +step_wise +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/class/thermal/thermal_zone0/temp +Lines: 1 +49925 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/class/thermal/thermal_zone0/type +Lines: 1 +bcm2835_thermal +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/class/thermal/thermal_zone1 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/class/thermal/thermal_zone1/mode +Lines: 1 +enabled +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/class/thermal/thermal_zone1/passive +Lines: 1 +0 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/class/thermal/thermal_zone1/policy +Lines: 1 +step_wise +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/class/thermal/thermal_zone1/temp +Lines: 1 +44000 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/class/thermal/thermal_zone1/type +Lines: 1 +acpitz +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Directory: fixtures/devices Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go b/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go index c90f569c..3ea56d05 100644 --- a/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go +++ b/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go @@ -16,7 +16,6 @@ package sysfs import ( - "fmt" "os" "path/filepath" "strings" @@ -26,16 +25,19 @@ import ( // SystemCPUCpufreqStats contains stats from devices/system/cpu/cpu[0-9]*/cpufreq/... type SystemCPUCpufreqStats struct { - Name string - CurrentFrequency uint64 - MinimumFrequency uint64 - MaximumFrequency uint64 - TransitionLatency uint64 - AvailableGovernors string - Driver string - Govenor string - RelatedCpus string - SetSpeed string + Name string + CpuinfoCurrentFrequency *uint64 + CpuinfoMinimumFrequency *uint64 + CpuinfoMaximumFrequency *uint64 + CpuinfoTransitionLatency *uint64 + ScalingCurrentFrequency *uint64 + ScalingMinimumFrequency *uint64 + ScalingMaximumFrequency *uint64 + AvailableGovernors string + Driver string + Govenor string + RelatedCpus string + SetSpeed string } // TODO: Add topology support. @@ -74,14 +76,7 @@ func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) { return []SystemCPUCpufreqStats{}, err } - if _, err = os.Stat(filepath.Join(cpuCpufreqPath, "scaling_cur_freq")); err == nil { - cpufreq, err = parseCpufreqCpuinfo("scaling", cpuCpufreqPath) - } else if _, err = os.Stat(filepath.Join(cpuCpufreqPath, "cpuinfo_cur_freq")); err == nil { - // Older kernels have metrics named `cpuinfo_...`. - cpufreq, err = parseCpufreqCpuinfo("cpuinfo", cpuCpufreqPath) - } else { - return []SystemCPUCpufreqStats{}, fmt.Errorf("CPU %v is missing cpufreq", cpu) - } + cpufreq, err = parseCpufreqCpuinfo(cpuCpufreqPath) if err != nil { return []SystemCPUCpufreqStats{}, err } @@ -92,22 +87,28 @@ func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) { return systemCpufreq, nil } -func parseCpufreqCpuinfo(prefix string, cpuPath string) (*SystemCPUCpufreqStats, error) { +func parseCpufreqCpuinfo(cpuPath string) (*SystemCPUCpufreqStats, error) { uintFiles := []string{ - prefix + "_cur_freq", - prefix + "_max_freq", - prefix + "_min_freq", + "cpuinfo_cur_freq", + "cpuinfo_max_freq", + "cpuinfo_min_freq", "cpuinfo_transition_latency", + "scaling_cur_freq", + "scaling_max_freq", + "scaling_min_freq", } - uintOut := make([]uint64, len(uintFiles)) + uintOut := make([]*uint64, len(uintFiles)) for i, f := range uintFiles { v, err := util.ReadUintFromFile(filepath.Join(cpuPath, f)) if err != nil { + if os.IsNotExist(err) || os.IsPermission(err) { + continue + } return &SystemCPUCpufreqStats{}, err } - uintOut[i] = v + uintOut[i] = &v } stringFiles := []string{ @@ -128,14 +129,17 @@ func parseCpufreqCpuinfo(prefix string, cpuPath string) (*SystemCPUCpufreqStats, } return &SystemCPUCpufreqStats{ - CurrentFrequency: uintOut[0], - MaximumFrequency: uintOut[1], - MinimumFrequency: uintOut[2], - TransitionLatency: uintOut[3], - AvailableGovernors: stringOut[0], - Driver: stringOut[1], - Govenor: stringOut[2], - RelatedCpus: stringOut[3], - SetSpeed: stringOut[4], + CpuinfoCurrentFrequency: uintOut[0], + CpuinfoMaximumFrequency: uintOut[1], + CpuinfoMinimumFrequency: uintOut[2], + CpuinfoTransitionLatency: uintOut[3], + ScalingCurrentFrequency: uintOut[4], + ScalingMaximumFrequency: uintOut[5], + ScalingMinimumFrequency: uintOut[6], + AvailableGovernors: stringOut[0], + Driver: stringOut[1], + Govenor: stringOut[2], + RelatedCpus: stringOut[3], + SetSpeed: stringOut[4], }, nil } diff --git a/vendor/github.com/prometheus/procfs/xfs/parse.go b/vendor/github.com/prometheus/procfs/xfs/parse.go index 2bc0ef34..b3d8634d 100644 --- a/vendor/github.com/prometheus/procfs/xfs/parse.go +++ b/vendor/github.com/prometheus/procfs/xfs/parse.go @@ -43,15 +43,15 @@ func ParseStats(r io.Reader) (*Stats, error) { 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" + // fieldPushAil = "push_ail" + // fieldXstrat = "xstrat" + // fieldAbtb2 = "abtb2" + // fieldAbtc2 = "abtc2" + // fieldBmbt2 = "bmbt2" + // fieldIbt2 = "ibt2" + // fieldFibt2 = "fibt2" + // fieldQm = "qm" + // fieldDebug = "debug" ) var xfss Stats diff --git a/vendor/github.com/siebenmann/go-kstat/.gitignore b/vendor/github.com/siebenmann/go-kstat/.gitignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/vendor/github.com/siebenmann/go-kstat/Makefile b/vendor/github.com/siebenmann/go-kstat/Makefile new file mode 100644 index 00000000..8e9c2356 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/Makefile @@ -0,0 +1,5 @@ +all: + @echo "Use 'make doctext' on a Solaris/Illumos/etc machine" + +doctext: + godoc github.com/siebenmann/go-kstat >kstat-godoc.txt diff --git a/vendor/github.com/siebenmann/go-kstat/README b/vendor/github.com/siebenmann/go-kstat/README new file mode 100644 index 00000000..07bfb71e --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/README @@ -0,0 +1,37 @@ +Go-kstat provides a Go API for the kstat kernel statistics system +on Solaris, Illumos, OmniOS, and other Solaris derived systems. For +general information on kstats, see the kstat(1) and kstat(3kstat) +manpages. For more documentation on the details of the package, see +doc.go, kstat_solaris.go, types_solaris_amd64.go, and raw_solaris.go. + +This package is quite young, so the API may well change as I and +other people gain experience with using it. + +The API supports access to 'named' kstat statistics, IO statistics, +and the most common and useful sorts of 'raw' kstat statistics +(unix:0:sysinfo, unix:0:vminfo, unix:0:var, and mnt:*:mntinfo). +Other raw kstat statistics are not explicitly supported, but the +API provides some escape hatches for access to custom raw +statistics. + +This is a cgo-based package so it can't be cross compiled like a regular +Go package. It may also have bugs with memory management, since it +interacts with the Solaris kstat library and holds references to memory +that's been dynamically allocated in C. + +See kstat-godoc.txt for a text dump of the full godoc for the package. +Unfortunately Go tool limitations appear to make it impossible to see +full package documentat on anything except a Solaris machine (including +https://godoc.org/, sadly). + +Bug reports and other contributions are highly welcome. + +Author: + +Chris Siebenmann +https://github.com/siebenmann/go-kstat +https://utcc.utoronto.ca/~cks/space/blog/ + +(and elsewhere) + +Copyright: standard Go copyright diff --git a/vendor/github.com/siebenmann/go-kstat/doc.go b/vendor/github.com/siebenmann/go-kstat/doc.go new file mode 100644 index 00000000..5dce79dc --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/doc.go @@ -0,0 +1,106 @@ +// +// Package kstat provides a Go interface to the Solaris/OmniOS +// kstat(s) system for user-level access to a lot of kernel +// statistics. For more documentation on kstats, see kstat(1) and +// kstat(3kstat). +// +// The package can retrieve what are called 'named' kstat statistics, +// IO statistics, and the most common additional types of 'raw' +// statistics, which covers almost all kstats you will normally find +// in the kernel. You can see the names and types of other kstats, but +// not currently retrieve data for them. Named statistics are the most +// common type for general information; IO statistics are exported by +// disks and some other things. Supported additional raw kstats are +// unix:0:sysinfo, unix:0:vminfo, unix:0:var, and mnt:*:mntinfo. +// +// General usage for named statistics: call Open() to obtain a Token, +// then call GetNamed() on it to obtain Named(s) for specific +// statistics. Note that this always gives you the very latest value +// for the statistic. If you want a number of statistics from the same +// module:inst:name triplet (eg several network counters from the same +// network interface) and you want them to all have been gathered at +// the same time, you need to call .Lookup() to obtain a KStat and +// then repeatedly call its .GetNamed() (this is also slightly more +// efficient). +// +// The short version: a kstat is a collection of some related +// statistics, eg various network counters for a particular network +// interface. A Token is a handle for a collection of kstats. You go +// collection (Token) -> kstat (KStat) -> specific statistic (Named) +// in order to retrieve the value of a specific statistic. +// +// (IO stats are retrieved all at once with GetIO(), because they come +// to us from the kernel as one single struct so that's what you get.) +// +// This is a cgo-based package. Cross compilation is up to you. +// Goroutine safety is in no way guaranteed because the underlying +// C kstat library is probably not thread or goroutine safe (and +// there are some all-Go concurrency races involving .Close()). +// +// This package may leak memory, especially since the Solaris kstat +// manpage is not clear on the requirements here. However I believe +// it's reasonably memory safe. It's possible to totally corrupt +// memory with use-after-free errors if you do operations on kstats +// after calling Token.Close(), although we try to avoid that. +// +// NOTE: this package is quite young. The API may well change as +// I (and other people) gain more experience with it. +// +// PERFORMANCE +// +// In general this is not going to be as lean and mean as calling +// C directly, partly because of intrinsic CGo overheads and partly +// because we do more memory allocation and deallocation than a C +// program would (partly because we prioritize not leaking memory). +// +// SUPPORTED AND UNSUPPORTED KSTAT TYPES +// +// We support named kstats and IO kstats (KSTAT_TYPE_NAMED and +// KSTAT_TYPE_IO / kstat_io_t respectively). kstat(1) also knows about +// a number of magic specific 'raw' stats (which are generally custom +// C structs); of these we support unix:0:sysinfo, unix:0:vminfo, +// unix:0:var, and mnt:*:mntinfo for NFS filesystem mounts. +// +// In theory kstat supports general timer and interrupt stats. In +// practice there is no use of KSTAT_TYPE_TIMER in the current Illumos +// kernel source and very little use of KSTAT_TYPE_INTR (mostly by +// very old hardware drivers, although the vioif driver uses it too). +// Since I can't test KSTAT_TYPE_INTR stats, we don't currently +// support it. +// +// There are also a few additional KSTAT_TYPE_RAW raw stats that we +// don't support, mostly because they seem to be effectively obsolete. +// These specific raw stats can be found listed in the Illumos source +// code in cmd/stat/kstat/kstat.h in the ks_raw_lookup array. See +// cmd/stat/kstat/kstat.c for how they're interpreted. If you need +// access to one of these kstats, the KStat.CopyTo() and KStat.Raw() +// methods give you an escape hatch to roll your own. You'll probably +// need to use cgo to generate an appropriate Go struct that matches +// the C struct you need. My notes on this process may be helpful: +// +// https://utcc.utoronto.ca/~cks/space/blog/programming/GoCGoCompatibleStructs +// +// Author: Chris Siebenmann +// https://github.com/siebenmann/go-kstat +// +// Copyright: standard Go copyright. +// +// (If you're reading this documentation on a non-Solaris platform, +// you're probably not seeing the detailed API documentation for +// constants, types, and so on because of tooling limitations in godoc +// et al.) +// +package kstat + +// +// This exists in large part to give non-Solaris systems something +// that makes the package name visible. Otherwise eg goimports thinks +// that this is an empty package and deletes 'import ...' statements +// for it if you process a Go file that imports the package on a +// non-Solaris platform. +// +// Since this file exists, I've put the package-level documentation +// here to increase the odds that tools running on non-Solaris systems +// will be able to show you at least some documentation. +// +// This is a hack, and annoying. diff --git a/vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt b/vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt new file mode 100644 index 00000000..d848406c --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt @@ -0,0 +1,455 @@ +PACKAGE DOCUMENTATION + +package kstat + import "github.com/siebenmann/go-kstat" + + Package kstat provides a Go interface to the Solaris/OmniOS kstat(s) + system for user-level access to a lot of kernel statistics. For more + documentation on kstats, see kstat(1) and kstat(3kstat). + + The package can retrieve what are called 'named' kstat statistics, IO + statistics, and the most common additional types of 'raw' statistics, + which covers almost all kstats you will normally find in the kernel. You + can see the names and types of other kstats, but not currently retrieve + data for them. Named statistics are the most common type for general + information; IO statistics are exported by disks and some other things. + Supported additional raw kstats are unix:0:sysinfo, unix:0:vminfo, + unix:0:var, and mnt:*:mntinfo. + + General usage for named statistics: call Open() to obtain a Token, then + call GetNamed() on it to obtain Named(s) for specific statistics. Note + that this always gives you the very latest value for the statistic. If + you want a number of statistics from the same module:inst:name triplet + (eg several network counters from the same network interface) and you + want them to all have been gathered at the same time, you need to call + .Lookup() to obtain a KStat and then repeatedly call its .GetNamed() + (this is also slightly more efficient). + + The short version: a kstat is a collection of some related statistics, + eg various network counters for a particular network interface. A Token + is a handle for a collection of kstats. You go collection (Token) -> + kstat (KStat) -> specific statistic (Named) in order to retrieve the + value of a specific statistic. + + (IO stats are retrieved all at once with GetIO(), because they come to + us from the kernel as one single struct so that's what you get.) + + This is a cgo-based package. Cross compilation is up to you. Goroutine + safety is in no way guaranteed because the underlying C kstat library is + probably not thread or goroutine safe (and there are some all-Go + concurrency races involving .Close()). + + This package may leak memory, especially since the Solaris kstat manpage + is not clear on the requirements here. However I believe it's reasonably + memory safe. It's possible to totally corrupt memory with use-after-free + errors if you do operations on kstats after calling Token.Close(), + although we try to avoid that. + + NOTE: this package is quite young. The API may well change as I (and + other people) gain more experience with it. + + + PERFORMANCE + + In general this is not going to be as lean and mean as calling C + directly, partly because of intrinsic CGo overheads and partly because + we do more memory allocation and deallocation than a C program would + (partly because we prioritize not leaking memory). + + + SUPPORTED AND UNSUPPORTED KSTAT TYPES + + We support named kstats and IO kstats (KSTAT_TYPE_NAMED and + KSTAT_TYPE_IO / kstat_io_t respectively). kstat(1) also knows about a + number of magic specific 'raw' stats (which are generally custom C + structs); of these we support unix:0:sysinfo, unix:0:vminfo, unix:0:var, + and mnt:*:mntinfo for NFS filesystem mounts. + + In theory kstat supports general timer and interrupt stats. In practice + there is no use of KSTAT_TYPE_TIMER in the current Illumos kernel source + and very little use of KSTAT_TYPE_INTR (mostly by very old hardware + drivers, although the vioif driver uses it too). Since I can't test + KSTAT_TYPE_INTR stats, we don't currently support it. + + There are also a few additional KSTAT_TYPE_RAW raw stats that we don't + support, mostly because they seem to be effectively obsolete. These + specific raw stats can be found listed in the Illumos source code in + cmd/stat/kstat/kstat.h in the ks_raw_lookup array. See + cmd/stat/kstat/kstat.c for how they're interpreted. If you need access + to one of these kstats, the KStat.CopyTo() and KStat.Raw() methods give + you an escape hatch to roll your own. You'll probably need to use cgo to + generate an appropriate Go struct that matches the C struct you need. My + notes on this process may be helpful: + + https://utcc.utoronto.ca/~cks/space/blog/programming/GoCGoCompatibleStructs + + Author: Chris Siebenmann https://github.com/siebenmann/go-kstat + + Copyright: standard Go copyright. + + (If you're reading this documentation on a non-Solaris platform, you're + probably not seeing the detailed API documentation for constants, types, + and so on because of tooling limitations in godoc et al.) + +FUNCTIONS + +func CFieldString(src []int8) string + CFieldString converts a (null-terminated) C string embedded in an []int8 + slice to a (Go) string. The []int8 slice is likely to come from an + [N]int8 fixed-size field in a statistics struct. If there is no null in + the slice, the entire slice is returned. + + (The no-null behavior is common in C APIs; a string is often allowed to + exactly fill the field with no room for a trailing null.) + +TYPES + +type IO struct { + Nread uint64 + Nwritten uint64 + Reads uint32 + Writes uint32 + Wtime int64 + Wlentime int64 + Wlastupdate int64 + Rtime int64 + Rlentime int64 + Rlastupdate int64 + Wcnt uint32 + Rcnt uint32 +} + IO represents the entire collection of KStat (disk) IO statistics + exposed by an IoStat type KStat. + + Because IO is an exact copy of the C kstat_io_t structure from the + kernel, it does not have a Snaptime or KStat field. You must save that + information separately if you need it, perhaps by embedded the IO struct + as an anonymous struct in an additional struct of your own. + +type KSType int + KSType is the type of the data in a KStat. + +const ( + RawStat KSType = C.KSTAT_TYPE_RAW + NamedStat KSType = C.KSTAT_TYPE_NAMED + IntrStat KSType = C.KSTAT_TYPE_INTR + IoStat KSType = C.KSTAT_TYPE_IO + TimerStat KSType = C.KSTAT_TYPE_TIMER +) + The different types of data that a KStat may contain, ie these are the + value of a KStat.Type. We currently only support getting Named and IO + statistics. + +func (tp KSType) String() string + +type KStat struct { + Module string + Instance int + Name string + + // Class is eg 'net' or 'disk'. In kstat(1) it shows up as a + // ':class' statistic. + Class string + // Type is the type of kstat. + Type KSType + + // Creation time of a kstat in nanoseconds since sometime. + // See gethrtime(3) and kstat(3kstat). + Crtime int64 + // Snaptime is what kstat(1) reports as 'snaptime', the time + // that this data was obtained. As with Crtime, it is in + // nanoseconds since some arbitrary point in time. + // Snaptime may not be valid until .Refresh() or .GetNamed() + // has been called. + Snaptime int64 + // contains filtered or unexported fields +} + KStat is the access handle for the collection of statistics for a + particular module:instance:name kstat. + +func (k *KStat) AllNamed() ([]*Named, error) + AllNamed returns an array of all named statistics for a particular + named-type KStat. Entries are returned in no particular order. + +func (k *KStat) CopyTo(ptr interface{}) error + CopyTo copies a RawStat KStat into a struct that you supply a pointer + to. The size of the struct must exactly match the size of the RawStat's + data. + + CopyStat imposes conditions on the struct that you are copying to: it + must be composed entirely of primitive integer types with defined sizes + (intN and uintN), or arrays and structs that ultimately only contain + them. All fields should be exported. + + If you give CopyStat a bad argument, it generally panics. + + This API is provisional and may be changed or deleted. + +func (k *KStat) GetIO() (*IO, error) + GetIO retrieves the IO statistics data from an IoStat type KStat. It + always refreshes the KStat to provide current data. + + It corresponds to kstat_read() followed by getting a copy of ks_data + (which is a kstat_io_t). + +func (k *KStat) GetMntinfo() (*Mntinfo, error) + GetMntinfo retrieves a Mntinfo struct from a nfs:*:mntinfo KStat. It + does not force a refresh of the KStat. + +func (k *KStat) GetNamed(name string) (*Named, error) + GetNamed obtains a particular named statistic from a KStat. It does not + refresh the KStat's statistics data, so multiple calls to GetNamed on a + single KStat will get a coherent set of statistic values from it. + + It corresponds to kstat_data_lookup(). + +func (k *KStat) Raw() (*Raw, error) + Raw returns the raw byte data of a KStat. It may be called on any KStat. + It does not refresh the KStat's data. + +func (k *KStat) Refresh() error + Refresh the statistics data for a KStat. + + Note that this does not update any existing Named objects for statistics + from this KStat. You must re-do .GetNamed() to get new ones in order to + see any updates. + + Under the hood this does a kstat_read(). You don't need to call it + explicitly before obtaining statistics from a KStat. + +func (k *KStat) String() string + +func (k *KStat) Valid() bool + Valid returns true if a KStat is still valid after a Token.Update() call + has returned true. If a KStat becomes invalid after an update, its + fields remain available but you can no longer call methods on it. You + may be able to look it up again with token.Lookup(k.Module, k.Instance, + k.Name), although it's possible that the module:instance:name now refers + to something else. Even if it is still the same thing, there is no + continuity in the actual statistics once Valid becomes false; you must + restart tracking from scratch. + + (For example, if one disk is removed from the system and another is + added, the new disk may use the same module:instance:name as some of the + old disk's KStats. Your .Lookup() may succeed, but what you get back is + not in any way a continuation of the old disk's information.) + + Valid also returns false after the KStat's token has been closed. + +type Mntinfo struct { + RProto [128]int8 + Vers uint32 + Flags uint32 + Secmod uint32 + Curread uint32 + Curwrite uint32 + Timeo int32 + Retrans int32 + Acregmin uint32 + Acregmax uint32 + Acdirmin uint32 + Acdirmax uint32 + Timers [4]struct { + Srtt uint32 + Deviate uint32 + Rtxcur uint32 + } + Noresponse uint32 + Failover uint32 + Remap uint32 + RCurserver [257]int8 + // contains filtered or unexported fields +} + Mntinfo is the kernel data from nfs:*:mntinfo, which is a 'struct + mntinfo_kstat'. Use .Proto() and .Curserver() to get the RProto and + RCurserver fields as strings instead of their awkward raw form. + +func (m Mntinfo) Curserver() string + Curserver returns a Mntinfo RCurserver as a string. + +func (m Mntinfo) Proto() string + Proto returns a Mntinfo RProto as a string. + +type Named struct { + Name string + Type NamedType + + // Only one of the following values is valid; the others are zero + // values. + // + // StringVal holds the value for both CharData and String Type(s). + StringVal string + IntVal int64 + UintVal uint64 + + // The Snaptime this Named was obtained. Note that while you + // use the parent KStat's Crtime, you cannot use its Snaptime. + // The KStat may have been refreshed since this Named was + // created, which updates the Snaptime. + Snaptime int64 + + // Pointer to the parent KStat, for access to the full name + // and the crtime associated with this Named. + KStat *KStat +} + Named represents a particular kstat named statistic, ie the full + + module:instance:name:statistic + + and its current value. + + Name and Type are always valid, but only one of StringVal, IntVal, or + UintVal is valid for any particular statistic; which one is valid is + determined by its Type. Generally you'll already know what type a given + named kstat statistic is; I don't believe Solaris changes their type + once they're defined. + +func (ks *Named) String() string + +type NamedType int + NamedType represents the various types of named kstat statistics. + +const ( + CharData NamedType = C.KSTAT_DATA_CHAR + Int32 NamedType = C.KSTAT_DATA_INT32 + Uint32 NamedType = C.KSTAT_DATA_UINT32 + Int64 NamedType = C.KSTAT_DATA_INT64 + Uint64 NamedType = C.KSTAT_DATA_UINT64 + String NamedType = C.KSTAT_DATA_STRING +) + The different types of data that a named kstat statistic can be (ie, + these are the potential values of Named.Type). + +func (tp NamedType) String() string + +type Raw struct { + Data []byte + Ndata uint64 + Snaptime int64 + KStat *KStat +} + Raw is the raw data of a KStat. The actual bytes are in Data; Ndata is + kstat_t.ks_ndata, and is not normally useful. + + Note that with RawStat KStats, it turns out that Ndata == len(Data). + This is contrary to its meaning for other types of kstats. + +type Sysinfo struct { + Updates uint32 + Runque uint32 + Runocc uint32 + Swpque uint32 + Swpocc uint32 + Waiting uint32 +} + Sysinfo is the data from unix:0:sysinfo, which is a sysinfo_t. + +type Token struct { + // contains filtered or unexported fields +} + Token is an access token for obtaining kstats. + +func Open() (*Token, error) + Open returns a kstat Token that is used to obtain kstats. It corresponds + to kstat_open(). You should call .Close() when you're done and then not + use any KStats or Nameds obtained through this token. + + (Failing to call .Close() will cause memory leaks.) + +func (t *Token) All() []*KStat + All returns an array of all available KStats. + + (It has no error return because due to how kstats are implemented, it + cannot fail.) + +func (t *Token) Close() error + Close a kstat access token. A closed token cannot be used for anything + and cannot be reopened. + + After a Token has been closed it remains safe to look at fields on KStat + and Named objects obtained through the Token, but it is not safe to call + methods on them other than String(); doing so may cause memory + corruption, although we try to avoid that. + + This corresponds to kstat_close(). + +func (t *Token) GetNamed(module string, instance int, name, stat string) (*Named, error) + GetNamed obtains the Named representing a particular (named) kstat + module:instance:name:statistic statistic. It always returns current data + for the kstat statistic, even if it's called repeatedly for the same + statistic. + + It is equivalent to .Lookup() then KStat.GetNamed(). + +func (t *Token) Lookup(module string, instance int, name string) (*KStat, error) + Lookup looks up a particular kstat. module and name may be "" and + instance may be -1 to mean 'the first one that kstats can find'. It also + refreshes (or retrieves) the kstat's data and thus sets Snaptime. + + Lookup() corresponds to kstat_lookup() *plus kstat_read()*. + +func (tok *Token) Sysinfo() (*KStat, *Sysinfo, error) + Sysinfo returns the KStat and the statistics from unix:0:sysinfo. It + always returns a current, refreshed copy. + +func (t *Token) Update() (bool, error) + Update synchronizes the Token to the current state of available kernel + kstats, returning true if the kernel's list of available kstats changed + and false otherwise. If there have been no changes in the kernel's kstat + list, all KStats remain valid. If there was a kstat update, some or all + of the KStats obtained through the Token may now be invalid. Some of the + now-invalid KStats may still exist and be the same thing, but if so they + will have to be looked up again. + + (This happens if, for example, a device disappears and then reappears. + At the kernel level, the device's kstat is deleted when it disappears + and then is recreated when it reappears; the kernel considers the + recreated version to be a different kstat, although it has the same + module:instance:name. Note that the same module:instance:name still + existing does not guarantee that the kstat is for the same thing; one + disk might have removed and then an entirely different new disk added.) + + Update corresponds to kstat_chain_update(). + +func (tok *Token) Var() (*KStat, *Var, error) + Var returns the KStat and the statistics from unix:0:var. It always + returns a current, refreshed copy. + +func (tok *Token) Vminfo() (*KStat, *Vminfo, error) + Vminfo returns the KStat and the statistics from unix:0:vminfo. It + always returns a current, refreshed copy. + +type Var struct { + Buf int32 + Call int32 + Proc int32 + Maxupttl int32 + Nglobpris int32 + Maxsyspri int32 + Clist int32 + Maxup int32 + Hbuf int32 + Hmask int32 + Pbuf int32 + Sptmap int32 + Maxpmem int32 + Autoup int32 + Bufhwm int32 +} + Var is the data from unix:0:var, which is a 'struct var'. + +type Vminfo struct { + Freemem uint64 + Resv uint64 + Alloc uint64 + Avail uint64 + Free uint64 + Updates uint64 +} + Vminfo is the data from unix:0:vminfo, which is a vminfo_t. + +SUBDIRECTORIES + + cmd + gen + diff --git a/vendor/github.com/siebenmann/go-kstat/kstat_solaris.go b/vendor/github.com/siebenmann/go-kstat/kstat_solaris.go new file mode 100644 index 00000000..55dac116 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/kstat_solaris.go @@ -0,0 +1,658 @@ +// +// The kstat package provides a Go interface to the Solaris/OmniOS +// kstat(s) system for user-level access to a lot of kernel +// statistics. For more documentation on kstats, see kstat(1) and +// kstat(3kstat). +// +// In an ideal world the package documentation would go here. This is +// not an ideal world, because any number of tools like godoc choke on +// Go files that are not for their architecture (although I'll admit +// it's a hard problem). So see doc.go for the actual package level +// documentation. +// +// However, I refuse to push function level API documentation off to another +// file, at least at the moment. It would be a horrible mess. +// + +package kstat + +// #cgo LDFLAGS: -lkstat +// +// #include +// #include +// #include +// #include +// +// /* We have to reach through unions, which cgo doesn't support. +// So we have our own cheesy little routines for it. These assume +// they are always being called on validly-typed named kstats. +// */ +// +// char *get_named_char(kstat_named_t *knp) { +// return knp->value.str.addr.ptr; +// } +// +// uint64_t get_named_uint(kstat_named_t *knp) { +// if (knp->data_type == KSTAT_DATA_UINT32) +// return knp->value.ui32; +// else +// return knp->value.ui64; +// } +// +// int64_t get_named_int(kstat_named_t *knp) { +// if (knp->data_type == KSTAT_DATA_INT32) +// return knp->value.i32; +// else +// return knp->value.i64; +// } +// +// /* Let's not try to do C pointer arithmetic in Go and get it wrong */ +// kstat_named_t *get_nth_named(kstat_t *ks, uint_t n) { +// kstat_named_t *knp; +// if (!ks || !ks->ks_data || ks->ks_type != KSTAT_TYPE_NAMED || n >= ks->ks_ndata) +// return NULL; +// knp = KSTAT_NAMED_PTR(ks); +// return knp + n; +// } +// +import "C" + +import ( + "errors" + "fmt" + "runtime" + "unsafe" +) + +// Token is an access token for obtaining kstats. +type Token struct { + kc *C.struct_kstat_ctl + + // ksm maps kstat_t pointers to our Go-level KStats for them. + // kstat_t's stay constant over the lifetime of a token, so + // we want to keep unique KStats. This holds some Go-level + // memory down, but I wave my hands. + ksm map[*C.struct_kstat]*KStat +} + +// Open returns a kstat Token that is used to obtain kstats. It corresponds +// to kstat_open(). You should call .Close() when you're done and then not +// use any KStats or Nameds obtained through this token. +// +// (Failing to call .Close() will cause memory leaks.) +func Open() (*Token, error) { + r, err := C.kstat_open() + if r == nil { + return nil, err + } + t := Token{} + t.kc = r + t.ksm = make(map[*C.struct_kstat]*KStat) + // A 'func (t *Token) Close()' is equivalent to + // 'func Close(t *Token)'. The latter is what SetFinalizer() + // needs. + runtime.SetFinalizer(&t, (*Token).Close) + return &t, nil +} + +// Close a kstat access token. A closed token cannot be used for +// anything and cannot be reopened. +// +// After a Token has been closed it remains safe to look at fields +// on KStat and Named objects obtained through the Token, but it is +// not safe to call methods on them other than String(); doing so +// may cause memory corruption, although we try to avoid that. +// +// This corresponds to kstat_close(). +func (t *Token) Close() error { + if t == nil || t.kc == nil { + return nil + } + + // Go through our KStats and null out fields that are no longer + // valid. We opt to do this before we actually destroy the memory + // KStat.ksp is pointing to by calling kstat_close(). + for _, v := range t.ksm { + v.ksp = nil + v.tok = nil + } + + res, err := C.kstat_close(t.kc) + t.kc = nil + + // clear the map to drop all references to KStats. + t.ksm = make(map[*C.struct_kstat]*KStat) + + // cancel finalizer + runtime.SetFinalizer(&t, nil) + + if res != 0 { + return err + } + return nil +} + +// Update synchronizes the Token to the current state of available +// kernel kstats, returning true if the kernel's list of available +// kstats changed and false otherwise. If there have been no changes +// in the kernel's kstat list, all KStats remain valid. If there was a +// kstat update, some or all of the KStats obtained through the Token +// may now be invalid. Some of the now-invalid KStats may still exist +// and be the same thing, but if so they will have to be looked up +// again. +// +// (This happens if, for example, a device disappears and then +// reappears. At the kernel level, the device's kstat is deleted when +// it disappears and then is recreated when it reappears; the kernel +// considers the recreated version to be a different kstat, although +// it has the same module:instance:name. Note that the same +// module:instance:name still existing does not guarantee that the +// kstat is for the same thing; one disk might have removed and then +// an entirely different new disk added.) +// +// Update corresponds to kstat_chain_update(). +func (t *Token) Update() (bool, error) { + if t == nil || t.kc == nil { + return true, errors.New("token is closed") + } + oid := t.kc.kc_chain_id + // NOTE that we can't assume err == nil on success and just + // check for err != nil. The error return is set from errno, + // and kstat_chain_update() does not guarantee that errno is + // 0 if it succeeds. + nid, err := C.kstat_chain_update(t.kc) + switch { + case nid < 0: + // We generously assume that if there has been an + // error, the chain is intact. Otherwise we should + // invalidate all KStats in t.ksm, as in .Close(). + // assumption: err != nil if n < 0. + return false, err + case nid == 0: + // No change is good news. + return false, nil + case nid == oid: + // Should never be the case, but... + return false, fmt.Errorf("new KCID is old KCID: %d", nid) + } + + // The simple approach to KStats after a chain update would be + // to invalidate all existing KStats. However, we can do + // better. kstat_chain_update() implicitly guarantees that it + // will not reuse memory addresses of kstat_t structures for + // different ones within a single call, so we can walk the + // chain and look for addresses that we already know; the + // KStats for those addresses are still valid. + + // Copy all valid chain entries that we have in the token ksm + // map to a new map and delete them from the old (current) map. + nksm := make(map[*C.struct_kstat]*KStat) + for r := t.kc.kc_chain; r != nil; r = r.ks_next { + if v, ok := t.ksm[r]; ok { + nksm[r] = v + delete(t.ksm, r) + } + } + // Anything left in t.ksm is an old chain entry that was + // removed by kstat_chain_update(). Explicitly zap their + // KStat's references to make them invalid. + for _, v := range t.ksm { + v.ksp = nil + v.tok = nil + } + // Make our new ksm map the current ksm map. + t.ksm = nksm + + return true, nil +} + +// All returns an array of all available KStats. +// +// (It has no error return because due to how kstats are implemented, +// it cannot fail.) +func (t *Token) All() []*KStat { + n := []*KStat{} + if t == nil || t.kc == nil { + return n + } + + for r := t.kc.kc_chain; r != nil; r = r.ks_next { + n = append(n, newKStat(t, r)) + } + return n +} + +// +// allocate a C string for a non-blank string; otherwise return nil +func maybeCString(src string) *C.char { + if src == "" { + return nil + } + return C.CString(src) +} + +// free a non-nil C string +func maybeFree(cs *C.char) { + if cs != nil { + C.free(unsafe.Pointer(cs)) + } +} + +// strndup behaves like the C function; given a *C.char and a len, it +// returns a string that is up to len characters long at most. +// Shorn of casts, it is: +// C.GoStringN(p, C.strnlen(p, len)) +// +// strndup() is necessary to copy fields of the type 'char +// name[SIZE];' where a string of exactly SIZE length will not be +// null-terminated. GoStringN() will always copy trailing null bytes +// and other garbage; GoString()'s internal strlen() may run off the +// end of the 'name' field and either fault or copy too much. +func strndup(cs *C.char, len C.size_t) string { + // credit: Ian Lance Taylor in + // https://github.com/golang/go/issues/12428 + return C.GoStringN(cs, C.int(C.strnlen(cs, len))) +} + +// Lookup looks up a particular kstat. module and name may be "" and +// instance may be -1 to mean 'the first one that kstats can find'. +// It also refreshes (or retrieves) the kstat's data and thus sets +// Snaptime. +// +// Lookup() corresponds to kstat_lookup() *plus kstat_read()*. +func (t *Token) Lookup(module string, instance int, name string) (*KStat, error) { + if t == nil || t.kc == nil { + return nil, errors.New("Token not valid or closed") + } + + ms := maybeCString(module) + ns := maybeCString(name) + r, err := C.kstat_lookup(t.kc, ms, C.int(instance), ns) + maybeFree(ms) + maybeFree(ns) + + if r == nil { + return nil, err + } + + k := newKStat(t, r) + + // People rarely look up kstats to not use them, so we immediately + // attempt to kstat_read() the data. If this fails, we don't return + // the kstat. However, we don't scrub it from the kstat_t mapping + // that the Token maintains; we have no reason to believe that it + // needs to be remade. Our return of nil is a convenience to avoid + // problems in callers. + // TODO: this may be a mistake in the API. + // + // NOTE: this means that calling Lookup() on an existing KStat + // (either directly or via tok.GetNamed()) has the effect of + // updating its statistics data to the current time. Right now + // we consider this a feature. + err = k.Refresh() + if err != nil { + return nil, err + } + return k, nil +} + +// GetNamed obtains the Named representing a particular (named) kstat +// module:instance:name:statistic statistic. It always returns current +// data for the kstat statistic, even if it's called repeatedly for the +// same statistic. +// +// It is equivalent to .Lookup() then KStat.GetNamed(). +func (t *Token) GetNamed(module string, instance int, name, stat string) (*Named, error) { + stats, err := t.Lookup(module, instance, name) + if err != nil { + return nil, err + } + return stats.GetNamed(stat) +} + +// ----- + +// KSType is the type of the data in a KStat. +type KSType int + +// The different types of data that a KStat may contain, ie these +// are the value of a KStat.Type. We currently only support getting +// Named and IO statistics. +const ( + RawStat KSType = C.KSTAT_TYPE_RAW + NamedStat KSType = C.KSTAT_TYPE_NAMED + IntrStat KSType = C.KSTAT_TYPE_INTR + IoStat KSType = C.KSTAT_TYPE_IO + TimerStat KSType = C.KSTAT_TYPE_TIMER +) + +func (tp KSType) String() string { + switch tp { + case RawStat: + return "raw" + case NamedStat: + return "named" + case IntrStat: + return "interrupt" + case IoStat: + return "io" + case TimerStat: + return "timer" + default: + return fmt.Sprintf("kstat_type:%d", tp) + } +} + +// KStat is the access handle for the collection of statistics for a +// particular module:instance:name kstat. +// +type KStat struct { + Module string + Instance int + Name string + + // Class is eg 'net' or 'disk'. In kstat(1) it shows up as a + // ':class' statistic. + Class string + // Type is the type of kstat. + Type KSType + + // Creation time of a kstat in nanoseconds since sometime. + // See gethrtime(3) and kstat(3kstat). + Crtime int64 + // Snaptime is what kstat(1) reports as 'snaptime', the time + // that this data was obtained. As with Crtime, it is in + // nanoseconds since some arbitrary point in time. + // Snaptime may not be valid until .Refresh() or .GetNamed() + // has been called. + Snaptime int64 + + ksp *C.struct_kstat + // We need access to the token to refresh the data + tok *Token +} + +// newKStat is our internal KStat constructor. +// +// This also has the responsibility of maintaining (and using) the +// kstat_t to KStat mapping cache, so that we don't recreate new +// KStats for the same kstat_t all the time. +func newKStat(tok *Token, ks *C.struct_kstat) *KStat { + if kst, ok := tok.ksm[ks]; ok { + return kst + } + + kst := KStat{} + kst.ksp = ks + kst.tok = tok + + kst.Instance = int(ks.ks_instance) + kst.Module = strndup((*C.char)(unsafe.Pointer(&ks.ks_module)), C.KSTAT_STRLEN) + kst.Name = strndup((*C.char)(unsafe.Pointer(&ks.ks_name)), C.KSTAT_STRLEN) + kst.Class = strndup((*C.char)(unsafe.Pointer(&ks.ks_class)), C.KSTAT_STRLEN) + kst.Type = KSType(ks.ks_type) + kst.Crtime = int64(ks.ks_crtime) + + // Inside the kernel, the ks_snaptime of a kstat is of course + // a global thing. This 'global' snaptime is copied to user + // level as part of the kstat header(s) on kstat_open(), which + // means that kstats that have never been kstat_read() by us + // are almost certain to have a non-zero ks_snaptime (because + // someone, somewhere, will have read them since the system + // booted, eg 'kstat -p | grep ...' reads all kstats). + // Because this ks_snaptime is not useful, we don't copy it + // to Snaptime; instead we leave Snaptime unset (zero) as + // an explicit signal that this KStat has never had its data + // read. + // + //kst.Snaptime = int64(ks.ks_snaptime) + + tok.ksm[ks] = &kst + return &kst +} + +// invalid is a desperate attempt to keep usage errors from causing +// memory corruption. Don't count on it. +func (k *KStat) invalid() bool { + return k == nil || k.ksp == nil || k.tok == nil || k.tok.kc == nil +} + +// setup does validity checks and setup, such as loading data via Refresh(). +// It applies only to named kstats. +// +// TODO: setup() vs prep() is a code smell. +func (k *KStat) setup() error { + if k.invalid() { + return errors.New("invalid KStat or closed token") + } + + if k.ksp.ks_type != C.KSTAT_TYPE_NAMED { + return fmt.Errorf("kstat %s (type %d) is not a named kstat", k, k.ksp.ks_type) + } + + // Do the initial load of the data if necessary. + if k.ksp.ks_data == nil { + if err := k.Refresh(); err != nil { + return err + } + } + return nil +} + +func (k *KStat) String() string { + return fmt.Sprintf("%s:%d:%s (%s)", k.Module, k.Instance, k.Name, k.Class) +} + +// Valid returns true if a KStat is still valid after a Token.Update() +// call has returned true. If a KStat becomes invalid after an update, +// its fields remain available but you can no longer call methods on +// it. You may be able to look it up again with token.Lookup(k.Module, +// k.Instance, k.Name), although it's possible that the +// module:instance:name now refers to something else. Even if it is +// still the same thing, there is no continuity in the actual +// statistics once Valid becomes false; you must restart tracking from +// scratch. +// +// (For example, if one disk is removed from the system and another is +// added, the new disk may use the same module:instance:name as some +// of the old disk's KStats. Your .Lookup() may succeed, but what you +// get back is not in any way a continuation of the old disk's +// information.) +// +// Valid also returns false after the KStat's token has been closed. +func (k *KStat) Valid() bool { + return !k.invalid() +} + +// Refresh the statistics data for a KStat. +// +// Note that this does not update any existing Named objects for +// statistics from this KStat. You must re-do .GetNamed() to get +// new ones in order to see any updates. +// +// Under the hood this does a kstat_read(). You don't need to call it +// explicitly before obtaining statistics from a KStat. +func (k *KStat) Refresh() error { + if k.invalid() { + return errors.New("invalid KStat or closed token") + } + + res, err := C.kstat_read(k.tok.kc, k.ksp, nil) + if res == -1 { + return err + } + k.Snaptime = int64(k.ksp.ks_snaptime) + return nil +} + +// GetIO retrieves the IO statistics data from an IoStat type +// KStat. It always refreshes the KStat to provide current data. +// +// It corresponds to kstat_read() followed by getting a copy of +// ks_data (which is a kstat_io_t). +func (k *KStat) GetIO() (*IO, error) { + if err := k.Refresh(); err != nil { + return nil, err + } + if k.ksp.ks_type != C.KSTAT_TYPE_IO { + return nil, fmt.Errorf("kstat %s (type %d) is not an IO kstat", k, k.ksp.ks_type) + } + + // We make our own copy of ks_data (as an IO) so that we don't + // point into C-owned memory. 'go tool cgo -godef' apparently + // guarantees that the IO struct/type it creates has exactly + // the same in-memory layout as the C struct, so we can safely + // do this copy and expect to get good results. + io := IO{} + io = *((*IO)(k.ksp.ks_data)) + return &io, nil +} + +// GetNamed obtains a particular named statistic from a KStat. It does +// not refresh the KStat's statistics data, so multiple calls to +// GetNamed on a single KStat will get a coherent set of statistic +// values from it. +// +// It corresponds to kstat_data_lookup(). +func (k *KStat) GetNamed(name string) (*Named, error) { + if err := k.setup(); err != nil { + return nil, err + } + ns := C.CString(name) + r, err := C.kstat_data_lookup(k.ksp, ns) + C.free(unsafe.Pointer(ns)) + if r == nil || err != nil { + return nil, err + } + return newNamed(k, (*C.struct_kstat_named)(r)), err +} + +// AllNamed returns an array of all named statistics for a particular +// named-type KStat. Entries are returned in no particular order. +func (k *KStat) AllNamed() ([]*Named, error) { + if err := k.setup(); err != nil { + return nil, err + } + lst := make([]*Named, k.ksp.ks_ndata) + for i := C.uint_t(0); i < k.ksp.ks_ndata; i++ { + ks := C.get_nth_named(k.ksp, i) + if ks == nil { + panic("get_nth_named returned surprise nil") + } + lst[i] = newNamed(k, ks) + } + return lst, nil +} + +// Named represents a particular kstat named statistic, ie the full +// module:instance:name:statistic +// and its current value. +// +// Name and Type are always valid, but only one of StringVal, IntVal, +// or UintVal is valid for any particular statistic; which one is +// valid is determined by its Type. Generally you'll already know what +// type a given named kstat statistic is; I don't believe Solaris +// changes their type once they're defined. +type Named struct { + Name string + Type NamedType + + // Only one of the following values is valid; the others are zero + // values. + // + // StringVal holds the value for both CharData and String Type(s). + StringVal string + IntVal int64 + UintVal uint64 + + // The Snaptime this Named was obtained. Note that while you + // use the parent KStat's Crtime, you cannot use its Snaptime. + // The KStat may have been refreshed since this Named was + // created, which updates the Snaptime. + Snaptime int64 + + // Pointer to the parent KStat, for access to the full name + // and the crtime associated with this Named. + KStat *KStat +} + +func (ks *Named) String() string { + return fmt.Sprintf("%s:%d:%s:%s", ks.KStat.Module, ks.KStat.Instance, ks.KStat.Name, ks.Name) +} + +// NamedType represents the various types of named kstat statistics. +type NamedType int + +// The different types of data that a named kstat statistic can be +// (ie, these are the potential values of Named.Type). +const ( + CharData NamedType = C.KSTAT_DATA_CHAR + Int32 NamedType = C.KSTAT_DATA_INT32 + Uint32 NamedType = C.KSTAT_DATA_UINT32 + Int64 NamedType = C.KSTAT_DATA_INT64 + Uint64 NamedType = C.KSTAT_DATA_UINT64 + String NamedType = C.KSTAT_DATA_STRING + + // CharData is found in StringVal. At the moment we assume that + // it is a real string, because this matches how it seems to be + // used for short strings in the Solaris kernel. Someday we may + // find something that uses it as just a data dump for 16 bytes. + + // Solaris sys/kstat.h also has _FLOAT (5) and _DOUBLE (6) types, + // but labels them as obsolete. +) + +func (tp NamedType) String() string { + switch tp { + case CharData: + return "char" + case Int32: + return "int32" + case Uint32: + return "uint32" + case Int64: + return "int64" + case Uint64: + return "uint64" + case String: + return "string" + default: + return fmt.Sprintf("named_type-%d", tp) + } +} + +// Create a new Stat from the kstat_named_t +// We set the appropriate *Value field. +func newNamed(k *KStat, knp *C.struct_kstat_named) *Named { + st := Named{} + st.KStat = k + st.Name = strndup((*C.char)(unsafe.Pointer(&knp.name)), C.KSTAT_STRLEN) + st.Type = NamedType(knp.data_type) + st.Snaptime = k.Snaptime + + switch st.Type { + case String: + // The comments in sys/kstat.h explicitly guarantee + // that these strings are null-terminated, although + // knp.value.str.len also holds the length. + st.StringVal = C.GoString(C.get_named_char(knp)) + case CharData: + // Solaris/etc appears to use CharData for short strings + // so that they can be embedded directly into + // knp.value.c[16] instead of requiring an out of line + // allocation. In theory we may find someone who is + // using it as 128-bit ints or the like. + // However I scanned the Illumos kernel source and + // everyone using it appears to really be using it for + // strings. + st.StringVal = strndup((*C.char)(unsafe.Pointer(&knp.value)), 16) + case Int32, Int64: + st.IntVal = int64(C.get_named_int(knp)) + case Uint32, Uint64: + st.UintVal = uint64(C.get_named_uint(knp)) + default: + // TODO: should do better. + panic(fmt.Sprintf("unknown stat type: %d", st.Type)) + } + return &st +} diff --git a/vendor/github.com/siebenmann/go-kstat/raw_solaris.go b/vendor/github.com/siebenmann/go-kstat/raw_solaris.go new file mode 100644 index 00000000..98d71187 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/raw_solaris.go @@ -0,0 +1,236 @@ +// +// Really raw access to KStat data + +package kstat + +// #cgo LDFLAGS: -lkstat +// +// #include +// #include +// #include +// #include +// #include +// +import "C" +import ( + "errors" + "fmt" + "reflect" + "unsafe" +) + +// Raw is the raw data of a KStat. The actual bytes are in Data; +// Ndata is kstat_t.ks_ndata, and is not normally useful. +// +// Note that with RawStat KStats, it turns out that Ndata == len(Data). +// This is contrary to its meaning for other types of kstats. +type Raw struct { + Data []byte + Ndata uint64 + Snaptime int64 + KStat *KStat +} + +// TODO: better functionality split here +func (k *KStat) prep() error { + if k.invalid() { + return errors.New("invalid KStat or closed token") + } + + // Do the initial load of the data if necessary. + if k.ksp.ks_data == nil { + if err := k.Refresh(); err != nil { + return err + } + } + return nil +} + +// Raw returns the raw byte data of a KStat. It may be called on any +// KStat. It does not refresh the KStat's data. +func (k *KStat) Raw() (*Raw, error) { + if err := k.prep(); err != nil { + return nil, err + } + r := Raw{} + r.KStat = k + r.Snaptime = k.Snaptime + r.Ndata = uint64(k.ksp.ks_ndata) + // The forced C.int() conversion is dangerous, because C.int + // is not necessarily large enough to contain a + // size_t. However this is the interface that Go gives us, so + // we live with it. + r.Data = C.GoBytes(unsafe.Pointer(k.ksp.ks_data), C.int(k.ksp.ks_data_size)) + return &r, nil +} + +func (tok *Token) prepunix(name string, size uintptr) (*KStat, error) { + k, err := tok.Lookup("unix", 0, name) + if err != nil { + return nil, err + } + // TODO: handle better? + if k.ksp.ks_type != C.KSTAT_TYPE_RAW { + return nil, fmt.Errorf("%s is wrong type %s", k, k.Type) + } + if uintptr(k.ksp.ks_data_size) != size { + return nil, fmt.Errorf("%s is wrong size %d (should be %d)", k, k.ksp.ks_data_size, size) + } + return k, nil +} + +// Sysinfo returns the KStat and the statistics from unix:0:sysinfo. +// It always returns a current, refreshed copy. +func (tok *Token) Sysinfo() (*KStat, *Sysinfo, error) { + var si Sysinfo + k, err := tok.prepunix("sysinfo", unsafe.Sizeof(si)) + if err != nil { + return nil, nil, err + } + si = *((*Sysinfo)(k.ksp.ks_data)) + return k, &si, nil +} + +// Vminfo returns the KStat and the statistics from unix:0:vminfo. +// It always returns a current, refreshed copy. +func (tok *Token) Vminfo() (*KStat, *Vminfo, error) { + var vi Vminfo + k, err := tok.prepunix("vminfo", unsafe.Sizeof(vi)) + if err != nil { + return nil, nil, err + } + vi = *((*Vminfo)(k.ksp.ks_data)) + return k, &vi, nil +} + +// Var returns the KStat and the statistics from unix:0:var. +// It always returns a current, refreshed copy. +func (tok *Token) Var() (*KStat, *Var, error) { + var vi Var + k, err := tok.prepunix("var", unsafe.Sizeof(vi)) + if err != nil { + return nil, nil, err + } + vi = *((*Var)(k.ksp.ks_data)) + return k, &vi, nil +} + +// GetMntinfo retrieves a Mntinfo struct from a nfs:*:mntinfo KStat. +// It does not force a refresh of the KStat. +func (k *KStat) GetMntinfo() (*Mntinfo, error) { + var mi Mntinfo + if err := k.prep(); err != nil { + return nil, err + } + if k.Type != RawStat || k.Module != "nfs" || k.Name != "mntinfo" { + return nil, errors.New("KStat is not a Mntinfo kstat") + } + if uintptr(k.ksp.ks_data_size) != unsafe.Sizeof(mi) { + return nil, fmt.Errorf("KStat is wrong size %d (should be %d)", k.ksp.ks_data_size, unsafe.Sizeof(mi)) + } + mi = *((*Mntinfo)(k.ksp.ks_data)) + return &mi, nil +} + +// +// Support for copying semi-arbitrary structures out of raw +// KStats. +// + +// safeThing returns true if a given type is either a simple defined +// size primitive integer type or an array and/or struct composed +// entirely of safe things. A safe thing is entirely self contained +// and may be initialized from random memory without breaking Go's +// memory safety (although the values it contains may be garbage). +// +func safeThing(t reflect.Type) bool { + switch t.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return true + case reflect.Array: + // an array is safe if it's an array of something safe + return safeThing(t.Elem()) + case reflect.Struct: + // a struct is safe if all its components are safe + for i := 0; i < t.NumField(); i++ { + if !safeThing(t.Field(i).Type) { + return false + } + } + return true + default: + // other things are not safe. + return false + } +} + +// TODO: add floats to the supported list? It's unlikely to be needed +// but it should just work. + +// CopyTo copies a RawStat KStat into a struct that you supply a +// pointer to. The size of the struct must exactly match the size of +// the RawStat's data. +// +// CopyStat imposes conditions on the struct that you are copying to: +// it must be composed entirely of primitive integer types with defined +// sizes (intN and uintN), or arrays and structs that ultimately only +// contain them. All fields should be exported. +// +// If you give CopyStat a bad argument, it generally panics. +// +// This API is provisional and may be changed or deleted. +func (k *KStat) CopyTo(ptr interface{}) error { + if err := k.prep(); err != nil { + return err + } + + if k.Type != RawStat { + return errors.New("KStat is not a RawStat") + } + + // Validity checks: not nil value, not nil pointer value, + // is a pointer to struct. + if ptr == nil { + panic("CopyTo given nil pointer") + } + vp := reflect.ValueOf(ptr) + if vp.Kind() != reflect.Ptr { + panic("CopyTo not given a pointer") + } + if vp.IsNil() { + panic("CopyTo given nil pointer") + } + dst := vp.Elem() + if dst.Kind() != reflect.Struct { + panic("CopyTo: not pointer to struct") + } + // Is the struct safe to copy into, which means primitive types + // and structs/arrays of primitive types? + if !safeThing(dst.Type()) { + panic("CopyTo: not a safe structure, contains unsupported fields") + } + if !dst.CanSet() { + panic("CopyTo: struct cannot be set for some reason") + } + + // Verify that the size of the target struct matches the size + // of the raw KStat. + if uintptr(k.ksp.ks_data_size) != dst.Type().Size() { + return errors.New("struct size does not match KStat size") + } + + // The following is exactly the magic that we performed for + // specific types earlier. We take k.ksp.ks_data and turn + // it into a typed pointer to the target object's type: + // + // src := ((*)(k.kps.ks_data)) + src := reflect.NewAt(dst.Type(), unsafe.Pointer(k.ksp.ks_data)) + + // We now dereference that into the destination to copy the + // data: + // + // dst = *src + dst.Set(reflect.Indirect(src)) + + return nil +} diff --git a/vendor/github.com/siebenmann/go-kstat/types_solaris_amd64.go b/vendor/github.com/siebenmann/go-kstat/types_solaris_amd64.go new file mode 100644 index 00000000..bea09608 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/types_solaris_amd64.go @@ -0,0 +1,141 @@ +// +// Initially created by +// cgo -godefs ctypes_solaris.go +// +// Now contains edits for documentation. This is considered okay by me +// because these structs are not exactly likely to change any time +// soon; that would break API compatibility. +// +// This is specific to amd64. It's unlikely that Go will support +// 32-bit Solaris ('386'), but. + +package kstat + +// IO represents the entire collection of KStat (disk) IO statistics +// exposed by an IoStat type KStat. +// +// Because IO is an exact copy of the C kstat_io_t structure from the +// kernel, it does not have a Snaptime or KStat field. You must save +// that information separately if you need it, perhaps by embedded the +// IO struct as an anonymous struct in an additional struct of your +// own. +type IO struct { + Nread uint64 + Nwritten uint64 + Reads uint32 + Writes uint32 + Wtime int64 + Wlentime int64 + Wlastupdate int64 + Rtime int64 + Rlentime int64 + Rlastupdate int64 + Wcnt uint32 + Rcnt uint32 +} + +// Sysinfo is the data from unix:0:sysinfo, which is a sysinfo_t. +type Sysinfo struct { + Updates uint32 + Runque uint32 + Runocc uint32 + Swpque uint32 + Swpocc uint32 + Waiting uint32 +} + +// Vminfo is the data from unix:0:vminfo, which is a vminfo_t. +type Vminfo struct { + Freemem uint64 + Resv uint64 + Alloc uint64 + Avail uint64 + Free uint64 + Updates uint64 +} + +// Var is the data from unix:0:var, which is a 'struct var'. +type Var struct { + Buf int32 + Call int32 + Proc int32 + Maxupttl int32 + Nglobpris int32 + Maxsyspri int32 + Clist int32 + Maxup int32 + Hbuf int32 + Hmask int32 + Pbuf int32 + Sptmap int32 + Maxpmem int32 + Autoup int32 + Bufhwm int32 +} + +// Mntinfo is the kernel data from nfs:*:mntinfo, which is a 'struct +// mntinfo_kstat'. Use .Proto() and .Curserver() to get the RProto +// and RCurserver fields as strings instead of their awkward raw form. +type Mntinfo struct { + RProto [128]int8 + Vers uint32 + Flags uint32 + Secmod uint32 + Curread uint32 + Curwrite uint32 + Timeo int32 + Retrans int32 + Acregmin uint32 + Acregmax uint32 + Acdirmin uint32 + Acdirmax uint32 + Timers [4]struct { + Srtt uint32 + Deviate uint32 + Rtxcur uint32 + } + Noresponse uint32 + Failover uint32 + Remap uint32 + RCurserver [257]int8 + pad0 [3]byte +} + +// CFieldString converts a (null-terminated) C string embedded in an +// []int8 slice to a (Go) string. The []int8 slice is likely to come +// from an [N]int8 fixed-size field in a statistics struct. If there +// is no null in the slice, the entire slice is returned. +// +// (The no-null behavior is common in C APIs; a string is often allowed +// to exactly fill the field with no room for a trailing null.) +func CFieldString(src []int8) string { + slen := len(src) + buf := make([]byte, slen) + for i := 0; i < len(src); i++ { + buf[i] = byte(src[i]) + if src[i] == 0 { + slen = i + break + } + } + return string(buf[:slen]) +} + +// Proto returns a Mntinfo RProto as a string. +func (m Mntinfo) Proto() string { + return CFieldString(m.RProto[:]) +} + +// Curserver returns a Mntinfo RCurserver as a string. +func (m Mntinfo) Curserver() string { + return CFieldString(m.RCurserver[:]) +} + +// The Mntinfo type is not an exact conversion as produced by cgo; +// because the original struct mntinfo_kstat contains an embedded +// anonymously typed struct, it runs into +// https://github.com/golang/go/issues/5253. This version is manually +// produced from a cgo starting point and then verified to be the same +// size. +// It also has Proto and Curserver renamed so we can add methods to +// get them as Go strings. diff --git a/vendor/modules.txt b/vendor/modules.txt index dbd7d5f7..25bff14e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -43,7 +43,7 @@ github.com/prometheus/common/version github.com/prometheus/common/expfmt github.com/prometheus/common/model github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg -# github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d +# github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5 github.com/prometheus/procfs github.com/prometheus/procfs/bcache github.com/prometheus/procfs/nfs