Update procfs vendor (#1248)

Signed-off-by: Mark Knapp <mknapp@hudson-trading.com>
pull/1252/head
mknapphrt 2019-02-04 10:54:41 -05:00 committed by Ben Kochie
parent 7d150d5782
commit 7fbdd0ae93
26 changed files with 2200 additions and 156 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

2
go.mod
View File

@ -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

4
go.sum
View File

@ -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=

View File

@ -1 +1,2 @@
* Tobias Schmidt <tobidt@gmail.com>
* Tobias Schmidt <tobidt@gmail.com> @grobie
* Johannes 'fish' Ziemke <github@freigeist.org> @discordianfish

View File

@ -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

223
vendor/github.com/prometheus/procfs/Makefile.common generated vendored Normal file
View File

@ -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

1
vendor/github.com/prometheus/procfs/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/prometheus/procfs

View File

@ -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
}

View File

@ -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")

View File

@ -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
}

View File

@ -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<zone>
// for a single <zone>.
// 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
}

View File

@ -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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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
}

View File

@ -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

1
vendor/github.com/siebenmann/go-kstat/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
*~

5
vendor/github.com/siebenmann/go-kstat/Makefile generated vendored Normal file
View File

@ -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

37
vendor/github.com/siebenmann/go-kstat/README generated vendored Normal file
View File

@ -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

106
vendor/github.com/siebenmann/go-kstat/doc.go generated vendored Normal file
View File

@ -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.

455
vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt generated vendored Normal file
View File

@ -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

658
vendor/github.com/siebenmann/go-kstat/kstat_solaris.go generated vendored Normal file
View File

@ -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 <sys/types.h>
// #include <stdlib.h>
// #include <strings.h>
// #include <kstat.h>
//
// /* 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
}

236
vendor/github.com/siebenmann/go-kstat/raw_solaris.go generated vendored Normal file
View File

@ -0,0 +1,236 @@
//
// Really raw access to KStat data
package kstat
// #cgo LDFLAGS: -lkstat
//
// #include <sys/types.h>
// #include <stdlib.h>
// #include <strings.h>
// #include <kstat.h>
// #include <nfs/nfs_clnt.h>
//
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 := ((*<type>)(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
}

View File

@ -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.

2
vendor/modules.txt vendored
View File

@ -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