diff options
author | mknapphrt <39998367+mknapphrt@users.noreply.github.com> | 2019-02-04 10:54:41 -0500 |
---|---|---|
committer | Ben Kochie <superq@gmail.com> | 2019-02-04 16:54:41 +0100 |
commit | 7fbdd0ae93bc792d103b39ffcd5bb92b270f8e35 (patch) | |
tree | f77f62301d684e588ea9e6afe101e7a6a295577f /vendor | |
parent | 7d150d578232f9fe4847035d0dd4b9ae9126d146 (diff) | |
download | prometheus_node_collector-7fbdd0ae93bc792d103b39ffcd5bb92b270f8e35.tar.bz2 prometheus_node_collector-7fbdd0ae93bc792d103b39ffcd5bb92b270f8e35.tar.xz prometheus_node_collector-7fbdd0ae93bc792d103b39ffcd5bb92b270f8e35.zip |
Update procfs vendor (#1248)
Signed-off-by: Mark Knapp <mknapp@hudson-trading.com>
Diffstat (limited to 'vendor')
20 files changed, 2092 insertions, 99 deletions
diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md index 35993c4..f1d3b99 100644 --- a/vendor/github.com/prometheus/procfs/MAINTAINERS.md +++ b/vendor/github.com/prometheus/procfs/MAINTAINERS.md | |||
@@ -1 +1,2 @@ | |||
1 | * Tobias Schmidt <tobidt@gmail.com> | 1 | * Tobias Schmidt <tobidt@gmail.com> @grobie |
2 | * Johannes 'fish' Ziemke <github@freigeist.org> @discordianfish | ||
diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile index 4d10983..947d7d8 100644 --- a/vendor/github.com/prometheus/procfs/Makefile +++ b/vendor/github.com/prometheus/procfs/Makefile | |||
@@ -11,49 +11,7 @@ | |||
11 | # See the License for the specific language governing permissions and | 11 | # See the License for the specific language governing permissions and |
12 | # limitations under the License. | 12 | # limitations under the License. |
13 | 13 | ||
14 | # Ensure GOBIN is not set during build so that promu is installed to the correct path | 14 | include Makefile.common |
15 | unexport GOBIN | ||
16 | |||
17 | GO ?= go | ||
18 | GOFMT ?= $(GO)fmt | ||
19 | FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) | ||
20 | STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck | ||
21 | pkgs = $(shell $(GO) list ./... | grep -v /vendor/) | ||
22 | |||
23 | PREFIX ?= $(shell pwd) | ||
24 | BIN_DIR ?= $(shell pwd) | ||
25 | |||
26 | ifdef DEBUG | ||
27 | bindata_flags = -debug | ||
28 | endif | ||
29 | |||
30 | STATICCHECK_IGNORE = | ||
31 | |||
32 | all: format staticcheck build test | ||
33 | |||
34 | style: | ||
35 | @echo ">> checking code style" | ||
36 | @! $(GOFMT) -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^' | ||
37 | |||
38 | check_license: | ||
39 | @echo ">> checking license header" | ||
40 | @./scripts/check_license.sh | ||
41 | |||
42 | test: fixtures/.unpacked sysfs/fixtures/.unpacked | ||
43 | @echo ">> running all tests" | ||
44 | @$(GO) test -race $(shell $(GO) list ./... | grep -v /vendor/ | grep -v examples) | ||
45 | |||
46 | format: | ||
47 | @echo ">> formatting code" | ||
48 | @$(GO) fmt $(pkgs) | ||
49 | |||
50 | vet: | ||
51 | @echo ">> vetting code" | ||
52 | @$(GO) vet $(pkgs) | ||
53 | |||
54 | staticcheck: $(STATICCHECK) | ||
55 | @echo ">> running staticcheck" | ||
56 | @$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) | ||
57 | 15 | ||
58 | %/.unpacked: %.ttar | 16 | %/.unpacked: %.ttar |
59 | ./ttar -C $(dir $*) -x -f $*.ttar | 17 | ./ttar -C $(dir $*) -x -f $*.ttar |
@@ -65,13 +23,8 @@ update_fixtures: fixtures.ttar sysfs/fixtures.ttar | |||
65 | rm -v $(dir $*)fixtures/.unpacked | 23 | rm -v $(dir $*)fixtures/.unpacked |
66 | ./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/ | 24 | ./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/ |
67 | 25 | ||
68 | $(FIRST_GOPATH)/bin/staticcheck: | 26 | .PHONY: build |
69 | @GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck | 27 | build: |
70 | |||
71 | .PHONY: all style check_license format test vet staticcheck | ||
72 | 28 | ||
73 | # Declaring the binaries at their default locations as PHONY targets is a hack | 29 | .PHONY: test |
74 | # to ensure the latest version is downloaded on every make execution. | 30 | test: fixtures/.unpacked sysfs/fixtures/.unpacked common-test |
75 | # If this is not desired, copy/symlink these binaries to a different path and | ||
76 | # set the respective environment variables. | ||
77 | .PHONY: $(GOPATH)/bin/staticcheck | ||
diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common new file mode 100644 index 0000000..741579e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/Makefile.common | |||
@@ -0,0 +1,223 @@ | |||
1 | # Copyright 2018 The Prometheus Authors | ||
2 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
3 | # you may not use this file except in compliance with the License. | ||
4 | # You may obtain a copy of the License at | ||
5 | # | ||
6 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
7 | # | ||
8 | # Unless required by applicable law or agreed to in writing, software | ||
9 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
11 | # See the License for the specific language governing permissions and | ||
12 | # limitations under the License. | ||
13 | |||
14 | |||
15 | # A common Makefile that includes rules to be reused in different prometheus projects. | ||
16 | # !!! Open PRs only against the prometheus/prometheus/Makefile.common repository! | ||
17 | |||
18 | # Example usage : | ||
19 | # Create the main Makefile in the root project directory. | ||
20 | # include Makefile.common | ||
21 | # customTarget: | ||
22 | # @echo ">> Running customTarget" | ||
23 | # | ||
24 | |||
25 | # Ensure GOBIN is not set during build so that promu is installed to the correct path | ||
26 | unexport GOBIN | ||
27 | |||
28 | GO ?= go | ||
29 | GOFMT ?= $(GO)fmt | ||
30 | FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) | ||
31 | GOOPTS ?= | ||
32 | |||
33 | GO_VERSION ?= $(shell $(GO) version) | ||
34 | GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) | ||
35 | PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') | ||
36 | |||
37 | unexport GOVENDOR | ||
38 | ifeq (, $(PRE_GO_111)) | ||
39 | ifneq (,$(wildcard go.mod)) | ||
40 | # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). | ||
41 | GO111MODULE := on | ||
42 | |||
43 | ifneq (,$(wildcard vendor)) | ||
44 | # Always use the local vendor/ directory to satisfy the dependencies. | ||
45 | GOOPTS := $(GOOPTS) -mod=vendor | ||
46 | endif | ||
47 | endif | ||
48 | else | ||
49 | ifneq (,$(wildcard go.mod)) | ||
50 | ifneq (,$(wildcard vendor)) | ||
51 | $(warning This repository requires Go >= 1.11 because of Go modules) | ||
52 | $(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') | ||
53 | endif | ||
54 | else | ||
55 | # This repository isn't using Go modules (yet). | ||
56 | GOVENDOR := $(FIRST_GOPATH)/bin/govendor | ||
57 | endif | ||
58 | |||
59 | unexport GO111MODULE | ||
60 | endif | ||
61 | PROMU := $(FIRST_GOPATH)/bin/promu | ||
62 | STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck | ||
63 | pkgs = ./... | ||
64 | |||
65 | GO_VERSION ?= $(shell $(GO) version) | ||
66 | GO_BUILD_PLATFORM ?= $(subst /,-,$(lastword $(GO_VERSION))) | ||
67 | |||
68 | PROMU_VERSION ?= 0.2.0 | ||
69 | PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz | ||
70 | |||
71 | PREFIX ?= $(shell pwd) | ||
72 | BIN_DIR ?= $(shell pwd) | ||
73 | DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) | ||
74 | DOCKER_REPO ?= prom | ||
75 | |||
76 | .PHONY: all | ||
77 | all: precheck style staticcheck unused build test | ||
78 | |||
79 | # This rule is used to forward a target like "build" to "common-build". This | ||
80 | # allows a new "build" target to be defined in a Makefile which includes this | ||
81 | # one and override "common-build" without override warnings. | ||
82 | %: common-% ; | ||
83 | |||
84 | .PHONY: common-style | ||
85 | common-style: | ||
86 | @echo ">> checking code style" | ||
87 | @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ | ||
88 | if [ -n "$${fmtRes}" ]; then \ | ||
89 | echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ | ||
90 | echo "Please ensure you are using $$($(GO) version) for formatting code."; \ | ||
91 | exit 1; \ | ||
92 | fi | ||
93 | |||
94 | .PHONY: common-check_license | ||
95 | common-check_license: | ||
96 | @echo ">> checking license header" | ||
97 | @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \ | ||
98 | awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \ | ||
99 | done); \ | ||
100 | if [ -n "$${licRes}" ]; then \ | ||
101 | echo "license header checking failed:"; echo "$${licRes}"; \ | ||
102 | exit 1; \ | ||
103 | fi | ||
104 | |||
105 | .PHONY: common-test-short | ||
106 | common-test-short: | ||
107 | @echo ">> running short tests" | ||
108 | GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs) | ||
109 | |||
110 | .PHONY: common-test | ||
111 | common-test: | ||
112 | @echo ">> running all tests" | ||
113 | GO111MODULE=$(GO111MODULE) $(GO) test -race $(GOOPTS) $(pkgs) | ||
114 | |||
115 | .PHONY: common-format | ||
116 | common-format: | ||
117 | @echo ">> formatting code" | ||
118 | GO111MODULE=$(GO111MODULE) $(GO) fmt $(GOOPTS) $(pkgs) | ||
119 | |||
120 | .PHONY: common-vet | ||
121 | common-vet: | ||
122 | @echo ">> vetting code" | ||
123 | GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) | ||
124 | |||
125 | .PHONY: common-staticcheck | ||
126 | common-staticcheck: $(STATICCHECK) | ||
127 | @echo ">> running staticcheck" | ||
128 | ifdef GO111MODULE | ||
129 | GO111MODULE=$(GO111MODULE) $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" -checks "SA*" $(pkgs) | ||
130 | else | ||
131 | $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) | ||
132 | endif | ||
133 | |||
134 | .PHONY: common-unused | ||
135 | common-unused: $(GOVENDOR) | ||
136 | ifdef GOVENDOR | ||
137 | @echo ">> running check for unused packages" | ||
138 | @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' | ||
139 | else | ||
140 | ifdef GO111MODULE | ||
141 | @echo ">> running check for unused/missing packages in go.mod" | ||
142 | GO111MODULE=$(GO111MODULE) $(GO) mod tidy | ||
143 | @git diff --exit-code -- go.sum go.mod | ||
144 | ifneq (,$(wildcard vendor)) | ||
145 | @echo ">> running check for unused packages in vendor/" | ||
146 | GO111MODULE=$(GO111MODULE) $(GO) mod vendor | ||
147 | @git diff --exit-code -- go.sum go.mod vendor/ | ||
148 | endif | ||
149 | endif | ||
150 | endif | ||
151 | |||
152 | .PHONY: common-build | ||
153 | common-build: promu | ||
154 | @echo ">> building binaries" | ||
155 | GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) | ||
156 | |||
157 | .PHONY: common-tarball | ||
158 | common-tarball: promu | ||
159 | @echo ">> building release tarball" | ||
160 | $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) | ||
161 | |||
162 | .PHONY: common-docker | ||
163 | common-docker: | ||
164 | docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" . | ||
165 | |||
166 | .PHONY: common-docker-publish | ||
167 | common-docker-publish: | ||
168 | docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" | ||
169 | |||
170 | .PHONY: common-docker-tag-latest | ||
171 | common-docker-tag-latest: | ||
172 | docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):latest" | ||
173 | |||
174 | .PHONY: promu | ||
175 | promu: $(PROMU) | ||
176 | |||
177 | $(PROMU): | ||
178 | curl -s -L $(PROMU_URL) | tar -xvz -C /tmp | ||
179 | mkdir -v -p $(FIRST_GOPATH)/bin | ||
180 | cp -v /tmp/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(PROMU) | ||
181 | |||
182 | .PHONY: proto | ||
183 | proto: | ||
184 | @echo ">> generating code from proto files" | ||
185 | @./scripts/genproto.sh | ||
186 | |||
187 | .PHONY: $(STATICCHECK) | ||
188 | $(STATICCHECK): | ||
189 | ifdef GO111MODULE | ||
190 | # Get staticcheck from a temporary directory to avoid modifying the local go.{mod,sum}. | ||
191 | # See https://github.com/golang/go/issues/27643. | ||
192 | # For now, we are using the next branch of staticcheck because master isn't compatible yet with Go modules. | ||
193 | tmpModule=$$(mktemp -d 2>&1) && \ | ||
194 | mkdir -p $${tmpModule}/staticcheck && \ | ||
195 | cd "$${tmpModule}"/staticcheck && \ | ||
196 | GO111MODULE=on $(GO) mod init example.com/staticcheck && \ | ||
197 | GO111MODULE=on GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck@next && \ | ||
198 | rm -rf $${tmpModule}; | ||
199 | else | ||
200 | GOOS= GOARCH= GO111MODULE=off $(GO) get -u honnef.co/go/tools/cmd/staticcheck | ||
201 | endif | ||
202 | |||
203 | ifdef GOVENDOR | ||
204 | .PHONY: $(GOVENDOR) | ||
205 | $(GOVENDOR): | ||
206 | GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor | ||
207 | endif | ||
208 | |||
209 | .PHONY: precheck | ||
210 | precheck:: | ||
211 | |||
212 | define PRECHECK_COMMAND_template = | ||
213 | precheck:: $(1)_precheck | ||
214 | |||
215 | |||
216 | PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) | ||
217 | .PHONY: $(1)_precheck | ||
218 | $(1)_precheck: | ||
219 | @if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \ | ||
220 | echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \ | ||
221 | exit 1; \ | ||
222 | fi | ||
223 | endef | ||
diff --git a/vendor/github.com/prometheus/procfs/go.mod b/vendor/github.com/prometheus/procfs/go.mod new file mode 100644 index 0000000..e89ee6c --- /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 2ff228e..ca74889 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) { | |||
57 | } | 57 | } |
58 | return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) | 58 | return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) |
59 | } | 59 | } |
60 | |||
61 | // ParseBool parses a string into a boolean pointer. | ||
62 | func ParseBool(b string) *bool { | ||
63 | var truth bool | ||
64 | switch b { | ||
65 | case "enabled": | ||
66 | truth = true | ||
67 | case "disabled": | ||
68 | truth = false | ||
69 | default: | ||
70 | return nil | ||
71 | } | ||
72 | return &truth | ||
73 | } | ||
diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go index 7a8a1e0..fc385af 100644 --- a/vendor/github.com/prometheus/procfs/mountstats.go +++ b/vendor/github.com/prometheus/procfs/mountstats.go | |||
@@ -69,6 +69,8 @@ type MountStats interface { | |||
69 | type MountStatsNFS struct { | 69 | type MountStatsNFS struct { |
70 | // The version of statistics provided. | 70 | // The version of statistics provided. |
71 | StatVersion string | 71 | StatVersion string |
72 | // The optional mountaddr of the NFS mount. | ||
73 | MountAddress string | ||
72 | // The age of the NFS mount. | 74 | // The age of the NFS mount. |
73 | Age time.Duration | 75 | Age time.Duration |
74 | // Statistics related to byte counters for various operations. | 76 | // Statistics related to byte counters for various operations. |
@@ -317,6 +319,7 @@ func parseMount(ss []string) (*Mount, error) { | |||
317 | func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) { | 319 | func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) { |
318 | // Field indicators for parsing specific types of data | 320 | // Field indicators for parsing specific types of data |
319 | const ( | 321 | const ( |
322 | fieldOpts = "opts:" | ||
320 | fieldAge = "age:" | 323 | fieldAge = "age:" |
321 | fieldBytes = "bytes:" | 324 | fieldBytes = "bytes:" |
322 | fieldEvents = "events:" | 325 | fieldEvents = "events:" |
@@ -338,6 +341,13 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e | |||
338 | } | 341 | } |
339 | 342 | ||
340 | switch ss[0] { | 343 | switch ss[0] { |
344 | case fieldOpts: | ||
345 | for _, opt := range strings.Split(ss[1], ",") { | ||
346 | split := strings.Split(opt, "=") | ||
347 | if len(split) == 2 && split[0] == "mountaddr" { | ||
348 | stats.MountAddress = split[1] | ||
349 | } | ||
350 | } | ||
341 | case fieldAge: | 351 | case fieldAge: |
342 | // Age integer is in seconds | 352 | // Age integer is in seconds |
343 | d, err := time.ParseDuration(ss[1] + "s") | 353 | 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 3cf2a9f..e7c626a 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 { | |||
95 | // in clock ticks. | 95 | // in clock ticks. |
96 | Starttime uint64 | 96 | Starttime uint64 |
97 | // Virtual memory size in bytes. | 97 | // Virtual memory size in bytes. |
98 | VSize int | 98 | VSize uint |
99 | // Resident set size in pages. | 99 | // Resident set size in pages. |
100 | RSS int | 100 | RSS int |
101 | 101 | ||
@@ -164,7 +164,7 @@ func (p Proc) NewStat() (ProcStat, error) { | |||
164 | } | 164 | } |
165 | 165 | ||
166 | // VirtualMemory returns the virtual memory size in bytes. | 166 | // VirtualMemory returns the virtual memory size in bytes. |
167 | func (s ProcStat) VirtualMemory() int { | 167 | func (s ProcStat) VirtualMemory() uint { |
168 | return s.VSize | 168 | return s.VSize |
169 | } | 169 | } |
170 | 170 | ||
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 0000000..4f9cb9a --- /dev/null +++ b/vendor/github.com/prometheus/procfs/sysfs/class_thermal.go | |||
@@ -0,0 +1,99 @@ | |||
1 | // Copyright 2018 The Prometheus Authors | ||
2 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
3 | // you may not use this file except in compliance with the License. | ||
4 | // You may obtain a copy of the License at | ||
5 | // | ||
6 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
7 | // | ||
8 | // Unless required by applicable law or agreed to in writing, software | ||
9 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
11 | // See the License for the specific language governing permissions and | ||
12 | // limitations under the License. | ||
13 | |||
14 | // +build !windows | ||
15 | |||
16 | package sysfs | ||
17 | |||
18 | import ( | ||
19 | "os" | ||
20 | "path/filepath" | ||
21 | "strings" | ||
22 | |||
23 | "github.com/prometheus/procfs/internal/util" | ||
24 | ) | ||
25 | |||
26 | // ClassThermalZoneStats contains info from files in /sys/class/thermal/thermal_zone<zone> | ||
27 | // for a single <zone>. | ||
28 | // https://www.kernel.org/doc/Documentation/thermal/sysfs-api.txt | ||
29 | type ClassThermalZoneStats struct { | ||
30 | Name string // The name of the zone from the directory structure. | ||
31 | Type string // The type of thermal zone. | ||
32 | Temp uint64 // Temperature in millidegree Celsius. | ||
33 | Policy string // One of the various thermal governors used for a particular zone. | ||
34 | Mode *bool // Optional: One of the predefined values in [enabled, disabled]. | ||
35 | Passive *uint64 // Optional: millidegrees Celsius. (0 for disabled, > 1000 for enabled+value) | ||
36 | } | ||
37 | |||
38 | // NewClassThermalZoneStats returns Thermal Zone metrics for all zones. | ||
39 | func (fs FS) NewClassThermalZoneStats() ([]ClassThermalZoneStats, error) { | ||
40 | zones, err := filepath.Glob(fs.Path("class/thermal/thermal_zone[0-9]*")) | ||
41 | if err != nil { | ||
42 | return []ClassThermalZoneStats{}, err | ||
43 | } | ||
44 | |||
45 | var zoneStats = ClassThermalZoneStats{} | ||
46 | stats := make([]ClassThermalZoneStats, len(zones)) | ||
47 | for i, zone := range zones { | ||
48 | zoneName := strings.TrimPrefix(filepath.Base(zone), "thermal_zone") | ||
49 | |||
50 | zoneStats, err = parseClassThermalZone(zone) | ||
51 | if err != nil { | ||
52 | return []ClassThermalZoneStats{}, err | ||
53 | } | ||
54 | zoneStats.Name = zoneName | ||
55 | stats[i] = zoneStats | ||
56 | } | ||
57 | return stats, nil | ||
58 | } | ||
59 | |||
60 | func parseClassThermalZone(zone string) (ClassThermalZoneStats, error) { | ||
61 | // Required attributes. | ||
62 | zoneType, err := util.SysReadFile(filepath.Join(zone, "type")) | ||
63 | if err != nil { | ||
64 | return ClassThermalZoneStats{}, err | ||
65 | } | ||
66 | zonePolicy, err := util.SysReadFile(filepath.Join(zone, "policy")) | ||
67 | if err != nil { | ||
68 | return ClassThermalZoneStats{}, err | ||
69 | } | ||
70 | zoneTemp, err := util.ReadUintFromFile(filepath.Join(zone, "temp")) | ||
71 | if err != nil { | ||
72 | return ClassThermalZoneStats{}, err | ||
73 | } | ||
74 | |||
75 | // Optional attributes. | ||
76 | mode, err := util.SysReadFile(filepath.Join(zone, "mode")) | ||
77 | if err != nil && !os.IsNotExist(err) && !os.IsPermission(err) { | ||
78 | return ClassThermalZoneStats{}, err | ||
79 | } | ||
80 | zoneMode := util.ParseBool(mode) | ||
81 | |||
82 | var zonePassive *uint64 | ||
83 | passive, err := util.ReadUintFromFile(filepath.Join(zone, "passive")) | ||
84 | if os.IsNotExist(err) || os.IsPermission(err) { | ||
85 | zonePassive = nil | ||
86 | } else if err != nil { | ||
87 | return ClassThermalZoneStats{}, err | ||
88 | } else { | ||
89 | zonePassive = &passive | ||
90 | } | ||
91 | |||
92 | return ClassThermalZoneStats{ | ||
93 | Type: zoneType, | ||
94 | Policy: zonePolicy, | ||
95 | Temp: zoneTemp, | ||
96 | Mode: zoneMode, | ||
97 | Passive: zonePassive, | ||
98 | }, nil | ||
99 | } | ||
diff --git a/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar b/vendor/github.com/prometheus/procfs/sysfs/fixtures.ttar index c0ac683..33bdbdb 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 | |||
137 | 1 | 137 | 1 |
138 | Mode: 644 | 138 | Mode: 644 |
139 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 139 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
140 | Directory: fixtures/class/thermal | ||
141 | Mode: 775 | ||
142 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
143 | Directory: fixtures/class/thermal/thermal_zone0 | ||
144 | Mode: 775 | ||
145 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
146 | Path: fixtures/class/thermal/thermal_zone0/policy | ||
147 | Lines: 1 | ||
148 | step_wise | ||
149 | Mode: 664 | ||
150 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
151 | Path: fixtures/class/thermal/thermal_zone0/temp | ||
152 | Lines: 1 | ||
153 | 49925 | ||
154 | Mode: 664 | ||
155 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
156 | Path: fixtures/class/thermal/thermal_zone0/type | ||
157 | Lines: 1 | ||
158 | bcm2835_thermal | ||
159 | Mode: 664 | ||
160 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
161 | Directory: fixtures/class/thermal/thermal_zone1 | ||
162 | Mode: 755 | ||
163 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
164 | Path: fixtures/class/thermal/thermal_zone1/mode | ||
165 | Lines: 1 | ||
166 | enabled | ||
167 | Mode: 664 | ||
168 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
169 | Path: fixtures/class/thermal/thermal_zone1/passive | ||
170 | Lines: 1 | ||
171 | 0 | ||
172 | Mode: 664 | ||
173 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
174 | Path: fixtures/class/thermal/thermal_zone1/policy | ||
175 | Lines: 1 | ||
176 | step_wise | ||
177 | Mode: 664 | ||
178 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
179 | Path: fixtures/class/thermal/thermal_zone1/temp | ||
180 | Lines: 1 | ||
181 | 44000 | ||
182 | Mode: 664 | ||
183 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
184 | Path: fixtures/class/thermal/thermal_zone1/type | ||
185 | Lines: 1 | ||
186 | acpitz | ||
187 | Mode: 664 | ||
188 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
140 | Directory: fixtures/devices | 189 | Directory: fixtures/devices |
141 | Mode: 755 | 190 | Mode: 755 |
142 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 191 | # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
diff --git a/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go b/vendor/github.com/prometheus/procfs/sysfs/system_cpu.go index c90f569..3ea56d0 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 @@ | |||
16 | package sysfs | 16 | package sysfs |
17 | 17 | ||
18 | import ( | 18 | import ( |
19 | "fmt" | ||
20 | "os" | 19 | "os" |
21 | "path/filepath" | 20 | "path/filepath" |
22 | "strings" | 21 | "strings" |
@@ -26,16 +25,19 @@ import ( | |||
26 | 25 | ||
27 | // SystemCPUCpufreqStats contains stats from devices/system/cpu/cpu[0-9]*/cpufreq/... | 26 | // SystemCPUCpufreqStats contains stats from devices/system/cpu/cpu[0-9]*/cpufreq/... |
28 | type SystemCPUCpufreqStats struct { | 27 | type SystemCPUCpufreqStats struct { |
29 | Name string | 28 | Name string |
30 | CurrentFrequency uint64 | 29 | CpuinfoCurrentFrequency *uint64 |
31 | MinimumFrequency uint64 | 30 | CpuinfoMinimumFrequency *uint64 |
32 | MaximumFrequency uint64 | 31 | CpuinfoMaximumFrequency *uint64 |
33 | TransitionLatency uint64 | 32 | CpuinfoTransitionLatency *uint64 |
34 | AvailableGovernors string | 33 | ScalingCurrentFrequency *uint64 |
35 | Driver string | 34 | ScalingMinimumFrequency *uint64 |
36 | Govenor string | 35 | ScalingMaximumFrequency *uint64 |
37 | RelatedCpus string | 36 | AvailableGovernors string |
38 | SetSpeed string | 37 | Driver string |
38 | Govenor string | ||
39 | RelatedCpus string | ||
40 | SetSpeed string | ||
39 | } | 41 | } |
40 | 42 | ||
41 | // TODO: Add topology support. | 43 | // TODO: Add topology support. |
@@ -74,14 +76,7 @@ func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) { | |||
74 | return []SystemCPUCpufreqStats{}, err | 76 | return []SystemCPUCpufreqStats{}, err |
75 | } | 77 | } |
76 | 78 | ||
77 | if _, err = os.Stat(filepath.Join(cpuCpufreqPath, "scaling_cur_freq")); err == nil { | 79 | cpufreq, err = parseCpufreqCpuinfo(cpuCpufreqPath) |
78 | cpufreq, err = parseCpufreqCpuinfo("scaling", cpuCpufreqPath) | ||
79 | } else if _, err = os.Stat(filepath.Join(cpuCpufreqPath, "cpuinfo_cur_freq")); err == nil { | ||
80 | // Older kernels have metrics named `cpuinfo_...`. | ||
81 | cpufreq, err = parseCpufreqCpuinfo("cpuinfo", cpuCpufreqPath) | ||
82 | } else { | ||
83 | return []SystemCPUCpufreqStats{}, fmt.Errorf("CPU %v is missing cpufreq", cpu) | ||
84 | } | ||
85 | if err != nil { | 80 | if err != nil { |
86 | return []SystemCPUCpufreqStats{}, err | 81 | return []SystemCPUCpufreqStats{}, err |
87 | } | 82 | } |
@@ -92,22 +87,28 @@ func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) { | |||
92 | return systemCpufreq, nil | 87 | return systemCpufreq, nil |
93 | } | 88 | } |
94 | 89 | ||
95 | func parseCpufreqCpuinfo(prefix string, cpuPath string) (*SystemCPUCpufreqStats, error) { | 90 | func parseCpufreqCpuinfo(cpuPath string) (*SystemCPUCpufreqStats, error) { |
96 | uintFiles := []string{ | 91 | uintFiles := []string{ |
97 | prefix + "_cur_freq", | 92 | "cpuinfo_cur_freq", |
98 | prefix + "_max_freq", | 93 | "cpuinfo_max_freq", |
99 | prefix + "_min_freq", | 94 | "cpuinfo_min_freq", |
100 | "cpuinfo_transition_latency", | 95 | "cpuinfo_transition_latency", |
96 | "scaling_cur_freq", | ||
97 | "scaling_max_freq", | ||
98 | "scaling_min_freq", | ||
101 | } | 99 | } |
102 | uintOut := make([]uint64, len(uintFiles)) | 100 | uintOut := make([]*uint64, len(uintFiles)) |
103 | 101 | ||
104 | for i, f := range uintFiles { | 102 | for i, f := range uintFiles { |
105 | v, err := util.ReadUintFromFile(filepath.Join(cpuPath, f)) | 103 | v, err := util.ReadUintFromFile(filepath.Join(cpuPath, f)) |
106 | if err != nil { | 104 | if err != nil { |
105 | if os.IsNotExist(err) || os.IsPermission(err) { | ||
106 | continue | ||
107 | } | ||
107 | return &SystemCPUCpufreqStats{}, err | 108 | return &SystemCPUCpufreqStats{}, err |
108 | } | 109 | } |
109 | 110 | ||
110 | uintOut[i] = v | 111 | uintOut[i] = &v |
111 | } | 112 | } |
112 | 113 | ||
113 | stringFiles := []string{ | 114 | stringFiles := []string{ |
@@ -128,14 +129,17 @@ func parseCpufreqCpuinfo(prefix string, cpuPath string) (*SystemCPUCpufreqStats, | |||
128 | } | 129 | } |
129 | 130 | ||
130 | return &SystemCPUCpufreqStats{ | 131 | return &SystemCPUCpufreqStats{ |
131 | CurrentFrequency: uintOut[0], | 132 | CpuinfoCurrentFrequency: uintOut[0], |
132 | MaximumFrequency: uintOut[1], | 133 | CpuinfoMaximumFrequency: uintOut[1], |
133 | MinimumFrequency: uintOut[2], | 134 | CpuinfoMinimumFrequency: uintOut[2], |
134 | TransitionLatency: uintOut[3], | 135 | CpuinfoTransitionLatency: uintOut[3], |
135 | AvailableGovernors: stringOut[0], | 136 | ScalingCurrentFrequency: uintOut[4], |
136 | Driver: stringOut[1], | 137 | ScalingMaximumFrequency: uintOut[5], |
137 | Govenor: stringOut[2], | 138 | ScalingMinimumFrequency: uintOut[6], |
138 | RelatedCpus: stringOut[3], | 139 | AvailableGovernors: stringOut[0], |
139 | SetSpeed: stringOut[4], | 140 | Driver: stringOut[1], |
141 | Govenor: stringOut[2], | ||
142 | RelatedCpus: stringOut[3], | ||
143 | SetSpeed: stringOut[4], | ||
140 | }, nil | 144 | }, nil |
141 | } | 145 | } |
diff --git a/vendor/github.com/prometheus/procfs/xfs/parse.go b/vendor/github.com/prometheus/procfs/xfs/parse.go index 2bc0ef3..b3d8634 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) { | |||
43 | fieldXpc = "xpc" | 43 | fieldXpc = "xpc" |
44 | 44 | ||
45 | // Unimplemented at this time due to lack of documentation. | 45 | // Unimplemented at this time due to lack of documentation. |
46 | fieldPushAil = "push_ail" | 46 | // fieldPushAil = "push_ail" |
47 | fieldXstrat = "xstrat" | 47 | // fieldXstrat = "xstrat" |
48 | fieldAbtb2 = "abtb2" | 48 | // fieldAbtb2 = "abtb2" |
49 | fieldAbtc2 = "abtc2" | 49 | // fieldAbtc2 = "abtc2" |
50 | fieldBmbt2 = "bmbt2" | 50 | // fieldBmbt2 = "bmbt2" |
51 | fieldIbt2 = "ibt2" | 51 | // fieldIbt2 = "ibt2" |
52 | fieldFibt2 = "fibt2" | 52 | // fieldFibt2 = "fibt2" |
53 | fieldQm = "qm" | 53 | // fieldQm = "qm" |
54 | fieldDebug = "debug" | 54 | // fieldDebug = "debug" |
55 | ) | 55 | ) |
56 | 56 | ||
57 | var xfss Stats | 57 | 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 0000000..b25c15b --- /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 0000000..8e9c235 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | all: | ||
2 | @echo "Use 'make doctext' on a Solaris/Illumos/etc machine" | ||
3 | |||
4 | doctext: | ||
5 | 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 0000000..07bfb71 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/README | |||
@@ -0,0 +1,37 @@ | |||
1 | Go-kstat provides a Go API for the kstat kernel statistics system | ||
2 | on Solaris, Illumos, OmniOS, and other Solaris derived systems. For | ||
3 | general information on kstats, see the kstat(1) and kstat(3kstat) | ||
4 | manpages. For more documentation on the details of the package, see | ||
5 | doc.go, kstat_solaris.go, types_solaris_amd64.go, and raw_solaris.go. | ||
6 | |||
7 | This package is quite young, so the API may well change as I and | ||
8 | other people gain experience with using it. | ||
9 | |||
10 | The API supports access to 'named' kstat statistics, IO statistics, | ||
11 | and the most common and useful sorts of 'raw' kstat statistics | ||
12 | (unix:0:sysinfo, unix:0:vminfo, unix:0:var, and mnt:*:mntinfo). | ||
13 | Other raw kstat statistics are not explicitly supported, but the | ||
14 | API provides some escape hatches for access to custom raw | ||
15 | statistics. | ||
16 | |||
17 | This is a cgo-based package so it can't be cross compiled like a regular | ||
18 | Go package. It may also have bugs with memory management, since it | ||
19 | interacts with the Solaris kstat library and holds references to memory | ||
20 | that's been dynamically allocated in C. | ||
21 | |||
22 | See kstat-godoc.txt for a text dump of the full godoc for the package. | ||
23 | Unfortunately Go tool limitations appear to make it impossible to see | ||
24 | full package documentat on anything except a Solaris machine (including | ||
25 | https://godoc.org/, sadly). | ||
26 | |||
27 | Bug reports and other contributions are highly welcome. | ||
28 | |||
29 | Author: | ||
30 | |||
31 | Chris Siebenmann | ||
32 | https://github.com/siebenmann/go-kstat | ||
33 | https://utcc.utoronto.ca/~cks/space/blog/ | ||
34 | |||
35 | (and elsewhere) | ||
36 | |||
37 | 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 0000000..5dce79d --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/doc.go | |||
@@ -0,0 +1,106 @@ | |||
1 | // | ||
2 | // Package kstat provides a Go interface to the Solaris/OmniOS | ||
3 | // kstat(s) system for user-level access to a lot of kernel | ||
4 | // statistics. For more documentation on kstats, see kstat(1) and | ||
5 | // kstat(3kstat). | ||
6 | // | ||
7 | // The package can retrieve what are called 'named' kstat statistics, | ||
8 | // IO statistics, and the most common additional types of 'raw' | ||
9 | // statistics, which covers almost all kstats you will normally find | ||
10 | // in the kernel. You can see the names and types of other kstats, but | ||
11 | // not currently retrieve data for them. Named statistics are the most | ||
12 | // common type for general information; IO statistics are exported by | ||
13 | // disks and some other things. Supported additional raw kstats are | ||
14 | // unix:0:sysinfo, unix:0:vminfo, unix:0:var, and mnt:*:mntinfo. | ||
15 | // | ||
16 | // General usage for named statistics: call Open() to obtain a Token, | ||
17 | // then call GetNamed() on it to obtain Named(s) for specific | ||
18 | // statistics. Note that this always gives you the very latest value | ||
19 | // for the statistic. If you want a number of statistics from the same | ||
20 | // module:inst:name triplet (eg several network counters from the same | ||
21 | // network interface) and you want them to all have been gathered at | ||
22 | // the same time, you need to call .Lookup() to obtain a KStat and | ||
23 | // then repeatedly call its .GetNamed() (this is also slightly more | ||
24 | // efficient). | ||
25 | // | ||
26 | // The short version: a kstat is a collection of some related | ||
27 | // statistics, eg various network counters for a particular network | ||
28 | // interface. A Token is a handle for a collection of kstats. You go | ||
29 | // collection (Token) -> kstat (KStat) -> specific statistic (Named) | ||
30 | // in order to retrieve the value of a specific statistic. | ||
31 | // | ||
32 | // (IO stats are retrieved all at once with GetIO(), because they come | ||
33 | // to us from the kernel as one single struct so that's what you get.) | ||
34 | // | ||
35 | // This is a cgo-based package. Cross compilation is up to you. | ||
36 | // Goroutine safety is in no way guaranteed because the underlying | ||
37 | // C kstat library is probably not thread or goroutine safe (and | ||
38 | // there are some all-Go concurrency races involving .Close()). | ||
39 | // | ||
40 | // This package may leak memory, especially since the Solaris kstat | ||
41 | // manpage is not clear on the requirements here. However I believe | ||
42 | // it's reasonably memory safe. It's possible to totally corrupt | ||
43 | // memory with use-after-free errors if you do operations on kstats | ||
44 | // after calling Token.Close(), although we try to avoid that. | ||
45 | // | ||
46 | // NOTE: this package is quite young. The API may well change as | ||
47 | // I (and other people) gain more experience with it. | ||
48 | // | ||
49 | // PERFORMANCE | ||
50 | // | ||
51 | // In general this is not going to be as lean and mean as calling | ||
52 | // C directly, partly because of intrinsic CGo overheads and partly | ||
53 | // because we do more memory allocation and deallocation than a C | ||
54 | // program would (partly because we prioritize not leaking memory). | ||
55 | // | ||
56 | // SUPPORTED AND UNSUPPORTED KSTAT TYPES | ||
57 | // | ||
58 | // We support named kstats and IO kstats (KSTAT_TYPE_NAMED and | ||
59 | // KSTAT_TYPE_IO / kstat_io_t respectively). kstat(1) also knows about | ||
60 | // a number of magic specific 'raw' stats (which are generally custom | ||
61 | // C structs); of these we support unix:0:sysinfo, unix:0:vminfo, | ||
62 | // unix:0:var, and mnt:*:mntinfo for NFS filesystem mounts. | ||
63 | // | ||
64 | // In theory kstat supports general timer and interrupt stats. In | ||
65 | // practice there is no use of KSTAT_TYPE_TIMER in the current Illumos | ||
66 | // kernel source and very little use of KSTAT_TYPE_INTR (mostly by | ||
67 | // very old hardware drivers, although the vioif driver uses it too). | ||
68 | // Since I can't test KSTAT_TYPE_INTR stats, we don't currently | ||
69 | // support it. | ||
70 | // | ||
71 | // There are also a few additional KSTAT_TYPE_RAW raw stats that we | ||
72 | // don't support, mostly because they seem to be effectively obsolete. | ||
73 | // These specific raw stats can be found listed in the Illumos source | ||
74 | // code in cmd/stat/kstat/kstat.h in the ks_raw_lookup array. See | ||
75 | // cmd/stat/kstat/kstat.c for how they're interpreted. If you need | ||
76 | // access to one of these kstats, the KStat.CopyTo() and KStat.Raw() | ||
77 | // methods give you an escape hatch to roll your own. You'll probably | ||
78 | // need to use cgo to generate an appropriate Go struct that matches | ||
79 | // the C struct you need. My notes on this process may be helpful: | ||
80 | // | ||
81 | // https://utcc.utoronto.ca/~cks/space/blog/programming/GoCGoCompatibleStructs | ||
82 | // | ||
83 | // Author: Chris Siebenmann | ||
84 | // https://github.com/siebenmann/go-kstat | ||
85 | // | ||
86 | // Copyright: standard Go copyright. | ||
87 | // | ||
88 | // (If you're reading this documentation on a non-Solaris platform, | ||
89 | // you're probably not seeing the detailed API documentation for | ||
90 | // constants, types, and so on because of tooling limitations in godoc | ||
91 | // et al.) | ||
92 | // | ||
93 | package kstat | ||
94 | |||
95 | // | ||
96 | // This exists in large part to give non-Solaris systems something | ||
97 | // that makes the package name visible. Otherwise eg goimports thinks | ||
98 | // that this is an empty package and deletes 'import ...' statements | ||
99 | // for it if you process a Go file that imports the package on a | ||
100 | // non-Solaris platform. | ||
101 | // | ||
102 | // Since this file exists, I've put the package-level documentation | ||
103 | // here to increase the odds that tools running on non-Solaris systems | ||
104 | // will be able to show you at least some documentation. | ||
105 | // | ||
106 | // 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 0000000..d848406 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/kstat-godoc.txt | |||
@@ -0,0 +1,455 @@ | |||
1 | PACKAGE DOCUMENTATION | ||
2 | |||
3 | package kstat | ||
4 | import "github.com/siebenmann/go-kstat" | ||
5 | |||
6 | Package kstat provides a Go interface to the Solaris/OmniOS kstat(s) | ||
7 | system for user-level access to a lot of kernel statistics. For more | ||
8 | documentation on kstats, see kstat(1) and kstat(3kstat). | ||
9 | |||
10 | The package can retrieve what are called 'named' kstat statistics, IO | ||
11 | statistics, and the most common additional types of 'raw' statistics, | ||
12 | which covers almost all kstats you will normally find in the kernel. You | ||
13 | can see the names and types of other kstats, but not currently retrieve | ||
14 | data for them. Named statistics are the most common type for general | ||
15 | information; IO statistics are exported by disks and some other things. | ||
16 | Supported additional raw kstats are unix:0:sysinfo, unix:0:vminfo, | ||
17 | unix:0:var, and mnt:*:mntinfo. | ||
18 | |||
19 | General usage for named statistics: call Open() to obtain a Token, then | ||
20 | call GetNamed() on it to obtain Named(s) for specific statistics. Note | ||
21 | that this always gives you the very latest value for the statistic. If | ||
22 | you want a number of statistics from the same module:inst:name triplet | ||
23 | (eg several network counters from the same network interface) and you | ||
24 | want them to all have been gathered at the same time, you need to call | ||
25 | .Lookup() to obtain a KStat and then repeatedly call its .GetNamed() | ||
26 | (this is also slightly more efficient). | ||
27 | |||
28 | The short version: a kstat is a collection of some related statistics, | ||
29 | eg various network counters for a particular network interface. A Token | ||
30 | is a handle for a collection of kstats. You go collection (Token) -> | ||
31 | kstat (KStat) -> specific statistic (Named) in order to retrieve the | ||
32 | value of a specific statistic. | ||
33 | |||
34 | (IO stats are retrieved all at once with GetIO(), because they come to | ||
35 | us from the kernel as one single struct so that's what you get.) | ||
36 | |||
37 | This is a cgo-based package. Cross compilation is up to you. Goroutine | ||
38 | safety is in no way guaranteed because the underlying C kstat library is | ||
39 | probably not thread or goroutine safe (and there are some all-Go | ||
40 | concurrency races involving .Close()). | ||
41 | |||
42 | This package may leak memory, especially since the Solaris kstat manpage | ||
43 | is not clear on the requirements here. However I believe it's reasonably | ||
44 | memory safe. It's possible to totally corrupt memory with use-after-free | ||
45 | errors if you do operations on kstats after calling Token.Close(), | ||
46 | although we try to avoid that. | ||
47 | |||
48 | NOTE: this package is quite young. The API may well change as I (and | ||
49 | other people) gain more experience with it. | ||
50 | |||
51 | |||
52 | PERFORMANCE | ||
53 | |||
54 | In general this is not going to be as lean and mean as calling C | ||
55 | directly, partly because of intrinsic CGo overheads and partly because | ||
56 | we do more memory allocation and deallocation than a C program would | ||
57 | (partly because we prioritize not leaking memory). | ||
58 | |||
59 | |||
60 | SUPPORTED AND UNSUPPORTED KSTAT TYPES | ||
61 | |||
62 | We support named kstats and IO kstats (KSTAT_TYPE_NAMED and | ||
63 | KSTAT_TYPE_IO / kstat_io_t respectively). kstat(1) also knows about a | ||
64 | number of magic specific 'raw' stats (which are generally custom C | ||
65 | structs); of these we support unix:0:sysinfo, unix:0:vminfo, unix:0:var, | ||
66 | and mnt:*:mntinfo for NFS filesystem mounts. | ||
67 | |||
68 | In theory kstat supports general timer and interrupt stats. In practice | ||
69 | there is no use of KSTAT_TYPE_TIMER in the current Illumos kernel source | ||
70 | and very little use of KSTAT_TYPE_INTR (mostly by very old hardware | ||
71 | drivers, although the vioif driver uses it too). Since I can't test | ||
72 | KSTAT_TYPE_INTR stats, we don't currently support it. | ||
73 | |||
74 | There are also a few additional KSTAT_TYPE_RAW raw stats that we don't | ||
75 | support, mostly because they seem to be effectively obsolete. These | ||
76 | specific raw stats can be found listed in the Illumos source code in | ||
77 | cmd/stat/kstat/kstat.h in the ks_raw_lookup array. See | ||
78 | cmd/stat/kstat/kstat.c for how they're interpreted. If you need access | ||
79 | to one of these kstats, the KStat.CopyTo() and KStat.Raw() methods give | ||
80 | you an escape hatch to roll your own. You'll probably need to use cgo to | ||
81 | generate an appropriate Go struct that matches the C struct you need. My | ||
82 | notes on this process may be helpful: | ||
83 | |||
84 | https://utcc.utoronto.ca/~cks/space/blog/programming/GoCGoCompatibleStructs | ||
85 | |||
86 | Author: Chris Siebenmann https://github.com/siebenmann/go-kstat | ||
87 | |||
88 | Copyright: standard Go copyright. | ||
89 | |||
90 | (If you're reading this documentation on a non-Solaris platform, you're | ||
91 | probably not seeing the detailed API documentation for constants, types, | ||
92 | and so on because of tooling limitations in godoc et al.) | ||
93 | |||
94 | FUNCTIONS | ||
95 | |||
96 | func CFieldString(src []int8) string | ||
97 | CFieldString converts a (null-terminated) C string embedded in an []int8 | ||
98 | slice to a (Go) string. The []int8 slice is likely to come from an | ||
99 | [N]int8 fixed-size field in a statistics struct. If there is no null in | ||
100 | the slice, the entire slice is returned. | ||
101 | |||
102 | (The no-null behavior is common in C APIs; a string is often allowed to | ||
103 | exactly fill the field with no room for a trailing null.) | ||
104 | |||
105 | TYPES | ||
106 | |||
107 | type IO struct { | ||
108 | Nread uint64 | ||
109 | Nwritten uint64 | ||
110 | Reads uint32 | ||
111 | Writes uint32 | ||
112 | Wtime int64 | ||
113 | Wlentime int64 | ||
114 | Wlastupdate int64 | ||
115 | Rtime int64 | ||
116 | Rlentime int64 | ||
117 | Rlastupdate int64 | ||
118 | Wcnt uint32 | ||
119 | Rcnt uint32 | ||
120 | } | ||
121 | IO represents the entire collection of KStat (disk) IO statistics | ||
122 | exposed by an IoStat type KStat. | ||
123 | |||
124 | Because IO is an exact copy of the C kstat_io_t structure from the | ||
125 | kernel, it does not have a Snaptime or KStat field. You must save that | ||
126 | information separately if you need it, perhaps by embedded the IO struct | ||
127 | as an anonymous struct in an additional struct of your own. | ||
128 | |||
129 | type KSType int | ||
130 | KSType is the type of the data in a KStat. | ||
131 | |||
132 | const ( | ||
133 | RawStat KSType = C.KSTAT_TYPE_RAW | ||
134 | NamedStat KSType = C.KSTAT_TYPE_NAMED | ||
135 | IntrStat KSType = C.KSTAT_TYPE_INTR | ||
136 | IoStat KSType = C.KSTAT_TYPE_IO | ||
137 | TimerStat KSType = C.KSTAT_TYPE_TIMER | ||
138 | ) | ||
139 | The different types of data that a KStat may contain, ie these are the | ||
140 | value of a KStat.Type. We currently only support getting Named and IO | ||
141 | statistics. | ||
142 | |||
143 | func (tp KSType) String() string | ||
144 | |||
145 | type KStat struct { | ||
146 | Module string | ||
147 | Instance int | ||
148 | Name string | ||
149 | |||
150 | // Class is eg 'net' or 'disk'. In kstat(1) it shows up as a | ||
151 | // ':class' statistic. | ||
152 | Class string | ||
153 | // Type is the type of kstat. | ||
154 | Type KSType | ||
155 | |||
156 | // Creation time of a kstat in nanoseconds since sometime. | ||
157 | // See gethrtime(3) and kstat(3kstat). | ||
158 | Crtime int64 | ||
159 | // Snaptime is what kstat(1) reports as 'snaptime', the time | ||
160 | // that this data was obtained. As with Crtime, it is in | ||
161 | // nanoseconds since some arbitrary point in time. | ||
162 | // Snaptime may not be valid until .Refresh() or .GetNamed() | ||
163 | // has been called. | ||
164 | Snaptime int64 | ||
165 | // contains filtered or unexported fields | ||
166 | } | ||
167 | KStat is the access handle for the collection of statistics for a | ||
168 | particular module:instance:name kstat. | ||
169 | |||
170 | func (k *KStat) AllNamed() ([]*Named, error) | ||
171 | AllNamed returns an array of all named statistics for a particular | ||
172 | named-type KStat. Entries are returned in no particular order. | ||
173 | |||
174 | func (k *KStat) CopyTo(ptr interface{}) error | ||
175 | CopyTo copies a RawStat KStat into a struct that you supply a pointer | ||
176 | to. The size of the struct must exactly match the size of the RawStat's | ||
177 | data. | ||
178 | |||
179 | CopyStat imposes conditions on the struct that you are copying to: it | ||
180 | must be composed entirely of primitive integer types with defined sizes | ||
181 | (intN and uintN), or arrays and structs that ultimately only contain | ||
182 | them. All fields should be exported. | ||
183 | |||
184 | If you give CopyStat a bad argument, it generally panics. | ||
185 | |||
186 | This API is provisional and may be changed or deleted. | ||
187 | |||
188 | func (k *KStat) GetIO() (*IO, error) | ||
189 | GetIO retrieves the IO statistics data from an IoStat type KStat. It | ||
190 | always refreshes the KStat to provide current data. | ||
191 | |||
192 | It corresponds to kstat_read() followed by getting a copy of ks_data | ||
193 | (which is a kstat_io_t). | ||
194 | |||
195 | func (k *KStat) GetMntinfo() (*Mntinfo, error) | ||
196 | GetMntinfo retrieves a Mntinfo struct from a nfs:*:mntinfo KStat. It | ||
197 | does not force a refresh of the KStat. | ||
198 | |||
199 | func (k *KStat) GetNamed(name string) (*Named, error) | ||
200 | GetNamed obtains a particular named statistic from a KStat. It does not | ||
201 | refresh the KStat's statistics data, so multiple calls to GetNamed on a | ||
202 | single KStat will get a coherent set of statistic values from it. | ||
203 | |||
204 | It corresponds to kstat_data_lookup(). | ||
205 | |||
206 | func (k *KStat) Raw() (*Raw, error) | ||
207 | Raw returns the raw byte data of a KStat. It may be called on any KStat. | ||
208 | It does not refresh the KStat's data. | ||
209 | |||
210 | func (k *KStat) Refresh() error | ||
211 | Refresh the statistics data for a KStat. | ||
212 | |||
213 | Note that this does not update any existing Named objects for statistics | ||
214 | from this KStat. You must re-do .GetNamed() to get new ones in order to | ||
215 | see any updates. | ||
216 | |||
217 | Under the hood this does a kstat_read(). You don't need to call it | ||
218 | explicitly before obtaining statistics from a KStat. | ||
219 | |||
220 | func (k *KStat) String() string | ||
221 | |||
222 | func (k *KStat) Valid() bool | ||
223 | Valid returns true if a KStat is still valid after a Token.Update() call | ||
224 | has returned true. If a KStat becomes invalid after an update, its | ||
225 | fields remain available but you can no longer call methods on it. You | ||
226 | may be able to look it up again with token.Lookup(k.Module, k.Instance, | ||
227 | k.Name), although it's possible that the module:instance:name now refers | ||
228 | to something else. Even if it is still the same thing, there is no | ||
229 | continuity in the actual statistics once Valid becomes false; you must | ||
230 | restart tracking from scratch. | ||
231 | |||
232 | (For example, if one disk is removed from the system and another is | ||
233 | added, the new disk may use the same module:instance:name as some of the | ||
234 | old disk's KStats. Your .Lookup() may succeed, but what you get back is | ||
235 | not in any way a continuation of the old disk's information.) | ||
236 | |||
237 | Valid also returns false after the KStat's token has been closed. | ||
238 | |||
239 | type Mntinfo struct { | ||
240 | RProto [128]int8 | ||
241 | Vers uint32 | ||
242 | Flags uint32 | ||
243 | Secmod uint32 | ||
244 | Curread uint32 | ||
245 | Curwrite uint32 | ||
246 | Timeo int32 | ||
247 | Retrans int32 | ||
248 | Acregmin uint32 | ||
249 | Acregmax uint32 | ||
250 | Acdirmin uint32 | ||
251 | Acdirmax uint32 | ||
252 | Timers [4]struct { | ||
253 | Srtt uint32 | ||
254 | Deviate uint32 | ||
255 | Rtxcur uint32 | ||
256 | } | ||
257 | Noresponse uint32 | ||
258 | Failover uint32 | ||
259 | Remap uint32 | ||
260 | RCurserver [257]int8 | ||
261 | // contains filtered or unexported fields | ||
262 | } | ||
263 | Mntinfo is the kernel data from nfs:*:mntinfo, which is a 'struct | ||
264 | mntinfo_kstat'. Use .Proto() and .Curserver() to get the RProto and | ||
265 | RCurserver fields as strings instead of their awkward raw form. | ||
266 | |||
267 | func (m Mntinfo) Curserver() string | ||
268 | Curserver returns a Mntinfo RCurserver as a string. | ||
269 | |||
270 | func (m Mntinfo) Proto() string | ||
271 | Proto returns a Mntinfo RProto as a string. | ||
272 | |||
273 | type Named struct { | ||
274 | Name string | ||
275 | Type NamedType | ||
276 | |||
277 | // Only one of the following values is valid; the others are zero | ||
278 | // values. | ||
279 | // | ||
280 | // StringVal holds the value for both CharData and String Type(s). | ||
281 | StringVal string | ||
282 | IntVal int64 | ||
283 | UintVal uint64 | ||
284 | |||
285 | // The Snaptime this Named was obtained. Note that while you | ||
286 | // use the parent KStat's Crtime, you cannot use its Snaptime. | ||
287 | // The KStat may have been refreshed since this Named was | ||
288 | // created, which updates the Snaptime. | ||
289 | Snaptime int64 | ||
290 | |||
291 | // Pointer to the parent KStat, for access to the full name | ||
292 | // and the crtime associated with this Named. | ||
293 | KStat *KStat | ||
294 | } | ||
295 | Named represents a particular kstat named statistic, ie the full | ||
296 | |||
297 | module:instance:name:statistic | ||
298 | |||
299 | and its current value. | ||
300 | |||
301 | Name and Type are always valid, but only one of StringVal, IntVal, or | ||
302 | UintVal is valid for any particular statistic; which one is valid is | ||
303 | determined by its Type. Generally you'll already know what type a given | ||
304 | named kstat statistic is; I don't believe Solaris changes their type | ||
305 | once they're defined. | ||
306 | |||
307 | func (ks *Named) String() string | ||
308 | |||
309 | type NamedType int | ||
310 | NamedType represents the various types of named kstat statistics. | ||
311 | |||
312 | const ( | ||
313 | CharData NamedType = C.KSTAT_DATA_CHAR | ||
314 | Int32 NamedType = C.KSTAT_DATA_INT32 | ||
315 | Uint32 NamedType = C.KSTAT_DATA_UINT32 | ||
316 | Int64 NamedType = C.KSTAT_DATA_INT64 | ||
317 | Uint64 NamedType = C.KSTAT_DATA_UINT64 | ||
318 | String NamedType = C.KSTAT_DATA_STRING | ||
319 | ) | ||
320 | The different types of data that a named kstat statistic can be (ie, | ||
321 | these are the potential values of Named.Type). | ||
322 | |||
323 | func (tp NamedType) String() string | ||
324 | |||
325 | type Raw struct { | ||
326 | Data []byte | ||
327 | Ndata uint64 | ||
328 | Snaptime int64 | ||
329 | KStat *KStat | ||
330 | } | ||
331 | Raw is the raw data of a KStat. The actual bytes are in Data; Ndata is | ||
332 | kstat_t.ks_ndata, and is not normally useful. | ||
333 | |||
334 | Note that with RawStat KStats, it turns out that Ndata == len(Data). | ||
335 | This is contrary to its meaning for other types of kstats. | ||
336 | |||
337 | type Sysinfo struct { | ||
338 | Updates uint32 | ||
339 | Runque uint32 | ||
340 | Runocc uint32 | ||
341 | Swpque uint32 | ||
342 | Swpocc uint32 | ||
343 | Waiting uint32 | ||
344 | } | ||
345 | Sysinfo is the data from unix:0:sysinfo, which is a sysinfo_t. | ||
346 | |||
347 | type Token struct { | ||
348 | // contains filtered or unexported fields | ||
349 | } | ||
350 | Token is an access token for obtaining kstats. | ||
351 | |||
352 | func Open() (*Token, error) | ||
353 | Open returns a kstat Token that is used to obtain kstats. It corresponds | ||
354 | to kstat_open(). You should call .Close() when you're done and then not | ||
355 | use any KStats or Nameds obtained through this token. | ||
356 | |||
357 | (Failing to call .Close() will cause memory leaks.) | ||
358 | |||
359 | func (t *Token) All() []*KStat | ||
360 | All returns an array of all available KStats. | ||
361 | |||
362 | (It has no error return because due to how kstats are implemented, it | ||
363 | cannot fail.) | ||
364 | |||
365 | func (t *Token) Close() error | ||
366 | Close a kstat access token. A closed token cannot be used for anything | ||
367 | and cannot be reopened. | ||
368 | |||
369 | After a Token has been closed it remains safe to look at fields on KStat | ||
370 | and Named objects obtained through the Token, but it is not safe to call | ||
371 | methods on them other than String(); doing so may cause memory | ||
372 | corruption, although we try to avoid that. | ||
373 | |||
374 | This corresponds to kstat_close(). | ||
375 | |||
376 | func (t *Token) GetNamed(module string, instance int, name, stat string) (*Named, error) | ||
377 | GetNamed obtains the Named representing a particular (named) kstat | ||
378 | module:instance:name:statistic statistic. It always returns current data | ||
379 | for the kstat statistic, even if it's called repeatedly for the same | ||
380 | statistic. | ||
381 | |||
382 | It is equivalent to .Lookup() then KStat.GetNamed(). | ||
383 | |||
384 | func (t *Token) Lookup(module string, instance int, name string) (*KStat, error) | ||
385 | Lookup looks up a particular kstat. module and name may be "" and | ||
386 | instance may be -1 to mean 'the first one that kstats can find'. It also | ||
387 | refreshes (or retrieves) the kstat's data and thus sets Snaptime. | ||
388 | |||
389 | Lookup() corresponds to kstat_lookup() *plus kstat_read()*. | ||
390 | |||
391 | func (tok *Token) Sysinfo() (*KStat, *Sysinfo, error) | ||
392 | Sysinfo returns the KStat and the statistics from unix:0:sysinfo. It | ||
393 | always returns a current, refreshed copy. | ||
394 | |||
395 | func (t *Token) Update() (bool, error) | ||
396 | Update synchronizes the Token to the current state of available kernel | ||
397 | kstats, returning true if the kernel's list of available kstats changed | ||
398 | and false otherwise. If there have been no changes in the kernel's kstat | ||
399 | list, all KStats remain valid. If there was a kstat update, some or all | ||
400 | of the KStats obtained through the Token may now be invalid. Some of the | ||
401 | now-invalid KStats may still exist and be the same thing, but if so they | ||
402 | will have to be looked up again. | ||
403 | |||
404 | (This happens if, for example, a device disappears and then reappears. | ||
405 | At the kernel level, the device's kstat is deleted when it disappears | ||
406 | and then is recreated when it reappears; the kernel considers the | ||
407 | recreated version to be a different kstat, although it has the same | ||
408 | module:instance:name. Note that the same module:instance:name still | ||
409 | existing does not guarantee that the kstat is for the same thing; one | ||
410 | disk might have removed and then an entirely different new disk added.) | ||
411 | |||
412 | Update corresponds to kstat_chain_update(). | ||
413 | |||
414 | func (tok *Token) Var() (*KStat, *Var, error) | ||
415 | Var returns the KStat and the statistics from unix:0:var. It always | ||
416 | returns a current, refreshed copy. | ||
417 | |||
418 | func (tok *Token) Vminfo() (*KStat, *Vminfo, error) | ||
419 | Vminfo returns the KStat and the statistics from unix:0:vminfo. It | ||
420 | always returns a current, refreshed copy. | ||
421 | |||
422 | type Var struct { | ||
423 | Buf int32 | ||
424 | Call int32 | ||
425 | Proc int32 | ||
426 | Maxupttl int32 | ||
427 | Nglobpris int32 | ||
428 | Maxsyspri int32 | ||
429 | Clist int32 | ||
430 | Maxup int32 | ||
431 | Hbuf int32 | ||
432 | Hmask int32 | ||
433 | Pbuf int32 | ||
434 | Sptmap int32 | ||
435 | Maxpmem int32 | ||
436 | Autoup int32 | ||
437 | Bufhwm int32 | ||
438 | } | ||
439 | Var is the data from unix:0:var, which is a 'struct var'. | ||
440 | |||
441 | type Vminfo struct { | ||
442 | Freemem uint64 | ||
443 | Resv uint64 | ||
444 | Alloc uint64 | ||
445 | Avail uint64 | ||
446 | Free uint64 | ||
447 | Updates uint64 | ||
448 | } | ||
449 | Vminfo is the data from unix:0:vminfo, which is a vminfo_t. | ||
450 | |||
451 | SUBDIRECTORIES | ||
452 | |||
453 | cmd | ||
454 | gen | ||
455 | |||
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 0000000..55dac11 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/kstat_solaris.go | |||
@@ -0,0 +1,658 @@ | |||
1 | // | ||
2 | // The kstat package provides a Go interface to the Solaris/OmniOS | ||
3 | // kstat(s) system for user-level access to a lot of kernel | ||
4 | // statistics. For more documentation on kstats, see kstat(1) and | ||
5 | // kstat(3kstat). | ||
6 | // | ||
7 | // In an ideal world the package documentation would go here. This is | ||
8 | // not an ideal world, because any number of tools like godoc choke on | ||
9 | // Go files that are not for their architecture (although I'll admit | ||
10 | // it's a hard problem). So see doc.go for the actual package level | ||
11 | // documentation. | ||
12 | // | ||
13 | // However, I refuse to push function level API documentation off to another | ||
14 | // file, at least at the moment. It would be a horrible mess. | ||
15 | // | ||
16 | |||
17 | package kstat | ||
18 | |||
19 | // #cgo LDFLAGS: -lkstat | ||
20 | // | ||
21 | // #include <sys/types.h> | ||
22 | // #include <stdlib.h> | ||
23 | // #include <strings.h> | ||
24 | // #include <kstat.h> | ||
25 | // | ||
26 | // /* We have to reach through unions, which cgo doesn't support. | ||
27 | // So we have our own cheesy little routines for it. These assume | ||
28 | // they are always being called on validly-typed named kstats. | ||
29 | // */ | ||
30 | // | ||
31 | // char *get_named_char(kstat_named_t *knp) { | ||
32 | // return knp->value.str.addr.ptr; | ||
33 | // } | ||
34 | // | ||
35 | // uint64_t get_named_uint(kstat_named_t *knp) { | ||
36 | // if (knp->data_type == KSTAT_DATA_UINT32) | ||
37 | // return knp->value.ui32; | ||
38 | // else | ||
39 | // return knp->value.ui64; | ||
40 | // } | ||
41 | // | ||
42 | // int64_t get_named_int(kstat_named_t *knp) { | ||
43 | // if (knp->data_type == KSTAT_DATA_INT32) | ||
44 | // return knp->value.i32; | ||
45 | // else | ||
46 | // return knp->value.i64; | ||
47 | // } | ||
48 | // | ||
49 | // /* Let's not try to do C pointer arithmetic in Go and get it wrong */ | ||
50 | // kstat_named_t *get_nth_named(kstat_t *ks, uint_t n) { | ||
51 | // kstat_named_t *knp; | ||
52 | // if (!ks || !ks->ks_data || ks->ks_type != KSTAT_TYPE_NAMED || n >= ks->ks_ndata) | ||
53 | // return NULL; | ||
54 | // knp = KSTAT_NAMED_PTR(ks); | ||
55 | // return knp + n; | ||
56 | // } | ||
57 | // | ||
58 | import "C" | ||
59 | |||
60 | import ( | ||
61 | "errors" | ||
62 | "fmt" | ||
63 | "runtime" | ||
64 | "unsafe" | ||
65 | ) | ||
66 | |||
67 | // Token is an access token for obtaining kstats. | ||
68 | type Token struct { | ||
69 | kc *C.struct_kstat_ctl | ||
70 | |||
71 | // ksm maps kstat_t pointers to our Go-level KStats for them. | ||
72 | // kstat_t's stay constant over the lifetime of a token, so | ||
73 | // we want to keep unique KStats. This holds some Go-level | ||
74 | // memory down, but I wave my hands. | ||
75 | ksm map[*C.struct_kstat]*KStat | ||
76 | } | ||
77 | |||
78 | // Open returns a kstat Token that is used to obtain kstats. It corresponds | ||
79 | // to kstat_open(). You should call .Close() when you're done and then not | ||
80 | // use any KStats or Nameds obtained through this token. | ||
81 | // | ||
82 | // (Failing to call .Close() will cause memory leaks.) | ||
83 | func Open() (*Token, error) { | ||
84 | r, err := C.kstat_open() | ||
85 | if r == nil { | ||
86 | return nil, err | ||
87 | } | ||
88 | t := Token{} | ||
89 | t.kc = r | ||
90 | t.ksm = make(map[*C.struct_kstat]*KStat) | ||
91 | // A 'func (t *Token) Close()' is equivalent to | ||
92 | // 'func Close(t *Token)'. The latter is what SetFinalizer() | ||
93 | // needs. | ||
94 | runtime.SetFinalizer(&t, (*Token).Close) | ||
95 | return &t, nil | ||
96 | } | ||
97 | |||
98 | // Close a kstat access token. A closed token cannot be used for | ||
99 | // anything and cannot be reopened. | ||
100 | // | ||
101 | // After a Token has been closed it remains safe to look at fields | ||
102 | // on KStat and Named objects obtained through the Token, but it is | ||
103 | // not safe to call methods on them other than String(); doing so | ||
104 | // may cause memory corruption, although we try to avoid that. | ||
105 | // | ||
106 | // This corresponds to kstat_close(). | ||
107 | func (t *Token) Close() error { | ||
108 | if t == nil || t.kc == nil { | ||
109 | return nil | ||
110 | } | ||
111 | |||
112 | // Go through our KStats and null out fields that are no longer | ||
113 | // valid. We opt to do this before we actually destroy the memory | ||
114 | // KStat.ksp is pointing to by calling kstat_close(). | ||
115 | for _, v := range t.ksm { | ||
116 | v.ksp = nil | ||
117 | v.tok = nil | ||
118 | } | ||
119 | |||
120 | res, err := C.kstat_close(t.kc) | ||
121 | t.kc = nil | ||
122 | |||
123 | // clear the map to drop all references to KStats. | ||
124 | t.ksm = make(map[*C.struct_kstat]*KStat) | ||
125 | |||
126 | // cancel finalizer | ||
127 | runtime.SetFinalizer(&t, nil) | ||
128 | |||
129 | if res != 0 { | ||
130 | return err | ||
131 | } | ||
132 | return nil | ||
133 | } | ||
134 | |||
135 | // Update synchronizes the Token to the current state of available | ||
136 | // kernel kstats, returning true if the kernel's list of available | ||
137 | // kstats changed and false otherwise. If there have been no changes | ||
138 | // in the kernel's kstat list, all KStats remain valid. If there was a | ||
139 | // kstat update, some or all of the KStats obtained through the Token | ||
140 | // may now be invalid. Some of the now-invalid KStats may still exist | ||
141 | // and be the same thing, but if so they will have to be looked up | ||
142 | // again. | ||
143 | // | ||
144 | // (This happens if, for example, a device disappears and then | ||
145 | // reappears. At the kernel level, the device's kstat is deleted when | ||
146 | // it disappears and then is recreated when it reappears; the kernel | ||
147 | // considers the recreated version to be a different kstat, although | ||
148 | // it has the same module:instance:name. Note that the same | ||
149 | // module:instance:name still existing does not guarantee that the | ||
150 | // kstat is for the same thing; one disk might have removed and then | ||
151 | // an entirely different new disk added.) | ||
152 | // | ||
153 | // Update corresponds to kstat_chain_update(). | ||
154 | func (t *Token) Update() (bool, error) { | ||
155 | if t == nil || t.kc == nil { | ||
156 | return true, errors.New("token is closed") | ||
157 | } | ||
158 | oid := t.kc.kc_chain_id | ||
159 | // NOTE that we can't assume err == nil on success and just | ||
160 | // check for err != nil. The error return is set from errno, | ||
161 | // and kstat_chain_update() does not guarantee that errno is | ||
162 | // 0 if it succeeds. | ||
163 | nid, err := C.kstat_chain_update(t.kc) | ||
164 | switch { | ||
165 | case nid < 0: | ||
166 | // We generously assume that if there has been an | ||
167 | // error, the chain is intact. Otherwise we should | ||
168 | // invalidate all KStats in t.ksm, as in .Close(). | ||
169 | // assumption: err != nil if n < 0. | ||
170 | return false, err | ||
171 | case nid == 0: | ||
172 | // No change is good news. | ||
173 | return false, nil | ||
174 | case nid == oid: | ||
175 | // Should never be the case, but... | ||
176 | return false, fmt.Errorf("new KCID is old KCID: %d", nid) | ||
177 | } | ||
178 | |||
179 | // The simple approach to KStats after a chain update would be | ||
180 | // to invalidate all existing KStats. However, we can do | ||
181 | // better. kstat_chain_update() implicitly guarantees that it | ||
182 | // will not reuse memory addresses of kstat_t structures for | ||
183 | // different ones within a single call, so we can walk the | ||
184 | // chain and look for addresses that we already know; the | ||
185 | // KStats for those addresses are still valid. | ||
186 | |||
187 | // Copy all valid chain entries that we have in the token ksm | ||
188 | // map to a new map and delete them from the old (current) map. | ||
189 | nksm := make(map[*C.struct_kstat]*KStat) | ||
190 | for r := t.kc.kc_chain; r != nil; r = r.ks_next { | ||
191 | if v, ok := t.ksm[r]; ok { | ||
192 | nksm[r] = v | ||
193 | delete(t.ksm, r) | ||
194 | } | ||
195 | } | ||
196 | // Anything left in t.ksm is an old chain entry that was | ||
197 | // removed by kstat_chain_update(). Explicitly zap their | ||
198 | // KStat's references to make them invalid. | ||
199 | for _, v := range t.ksm { | ||
200 | v.ksp = nil | ||
201 | v.tok = nil | ||
202 | } | ||
203 | // Make our new ksm map the current ksm map. | ||
204 | t.ksm = nksm | ||
205 | |||
206 | return true, nil | ||
207 | } | ||
208 | |||
209 | // All returns an array of all available KStats. | ||
210 | // | ||
211 | // (It has no error return because due to how kstats are implemented, | ||
212 | // it cannot fail.) | ||
213 | func (t *Token) All() []*KStat { | ||
214 | n := []*KStat{} | ||
215 | if t == nil || t.kc == nil { | ||
216 | return n | ||
217 | } | ||
218 | |||
219 | for r := t.kc.kc_chain; r != nil; r = r.ks_next { | ||
220 | n = append(n, newKStat(t, r)) | ||
221 | } | ||
222 | return n | ||
223 | } | ||
224 | |||
225 | // | ||
226 | // allocate a C string for a non-blank string; otherwise return nil | ||
227 | func maybeCString(src string) *C.char { | ||
228 | if src == "" { | ||
229 | return nil | ||
230 | } | ||
231 | return C.CString(src) | ||
232 | } | ||
233 | |||
234 | // free a non-nil C string | ||
235 | func maybeFree(cs *C.char) { | ||
236 | if cs != nil { | ||
237 | C.free(unsafe.Pointer(cs)) | ||
238 | } | ||
239 | } | ||
240 | |||
241 | // strndup behaves like the C function; given a *C.char and a len, it | ||
242 | // returns a string that is up to len characters long at most. | ||
243 | // Shorn of casts, it is: | ||
244 | // C.GoStringN(p, C.strnlen(p, len)) | ||
245 | // | ||
246 | // strndup() is necessary to copy fields of the type 'char | ||
247 | // name[SIZE];' where a string of exactly SIZE length will not be | ||
248 | // null-terminated. GoStringN() will always copy trailing null bytes | ||
249 | // and other garbage; GoString()'s internal strlen() may run off the | ||
250 | // end of the 'name' field and either fault or copy too much. | ||
251 | func strndup(cs *C.char, len C.size_t) string { | ||
252 | // credit: Ian Lance Taylor in | ||
253 | // https://github.com/golang/go/issues/12428 | ||
254 | return C.GoStringN(cs, C.int(C.strnlen(cs, len))) | ||
255 | } | ||
256 | |||
257 | // Lookup looks up a particular kstat. module and name may be "" and | ||
258 | // instance may be -1 to mean 'the first one that kstats can find'. | ||
259 | // It also refreshes (or retrieves) the kstat's data and thus sets | ||
260 | // Snaptime. | ||
261 | // | ||
262 | // Lookup() corresponds to kstat_lookup() *plus kstat_read()*. | ||
263 | func (t *Token) Lookup(module string, instance int, name string) (*KStat, error) { | ||
264 | if t == nil || t.kc == nil { | ||
265 | return nil, errors.New("Token not valid or closed") | ||
266 | } | ||
267 | |||
268 | ms := maybeCString(module) | ||
269 | ns := maybeCString(name) | ||
270 | r, err := C.kstat_lookup(t.kc, ms, C.int(instance), ns) | ||
271 | maybeFree(ms) | ||
272 | maybeFree(ns) | ||
273 | |||
274 | if r == nil { | ||
275 | return nil, err | ||
276 | } | ||
277 | |||
278 | k := newKStat(t, r) | ||
279 | |||
280 | // People rarely look up kstats to not use them, so we immediately | ||
281 | // attempt to kstat_read() the data. If this fails, we don't return | ||
282 | // the kstat. However, we don't scrub it from the kstat_t mapping | ||
283 | // that the Token maintains; we have no reason to believe that it | ||
284 | // needs to be remade. Our return of nil is a convenience to avoid | ||
285 | // problems in callers. | ||
286 | // TODO: this may be a mistake in the API. | ||
287 | // | ||
288 | // NOTE: this means that calling Lookup() on an existing KStat | ||
289 | // (either directly or via tok.GetNamed()) has the effect of | ||
290 | // updating its statistics data to the current time. Right now | ||
291 | // we consider this a feature. | ||
292 | err = k.Refresh() | ||
293 | if err != nil { | ||
294 | return nil, err | ||
295 | } | ||
296 | return k, nil | ||
297 | } | ||
298 | |||
299 | // GetNamed obtains the Named representing a particular (named) kstat | ||
300 | // module:instance:name:statistic statistic. It always returns current | ||
301 | // data for the kstat statistic, even if it's called repeatedly for the | ||
302 | // same statistic. | ||
303 | // | ||
304 | // It is equivalent to .Lookup() then KStat.GetNamed(). | ||
305 | func (t *Token) GetNamed(module string, instance int, name, stat string) (*Named, error) { | ||
306 | stats, err := t.Lookup(module, instance, name) | ||
307 | if err != nil { | ||
308 | return nil, err | ||
309 | } | ||
310 | return stats.GetNamed(stat) | ||
311 | } | ||
312 | |||
313 | // ----- | ||
314 | |||
315 | // KSType is the type of the data in a KStat. | ||
316 | type KSType int | ||
317 | |||
318 | // The different types of data that a KStat may contain, ie these | ||
319 | // are the value of a KStat.Type. We currently only support getting | ||
320 | // Named and IO statistics. | ||
321 | const ( | ||
322 | RawStat KSType = C.KSTAT_TYPE_RAW | ||
323 | NamedStat KSType = C.KSTAT_TYPE_NAMED | ||
324 | IntrStat KSType = C.KSTAT_TYPE_INTR | ||
325 | IoStat KSType = C.KSTAT_TYPE_IO | ||
326 | TimerStat KSType = C.KSTAT_TYPE_TIMER | ||
327 | ) | ||
328 | |||
329 | func (tp KSType) String() string { | ||
330 | switch tp { | ||
331 | case RawStat: | ||
332 | return "raw" | ||
333 | case NamedStat: | ||
334 | return "named" | ||
335 | case IntrStat: | ||
336 | return "interrupt" | ||
337 | case IoStat: | ||
338 | return "io" | ||
339 | case TimerStat: | ||
340 | return "timer" | ||
341 | default: | ||
342 | return fmt.Sprintf("kstat_type:%d", tp) | ||
343 | } | ||
344 | } | ||
345 | |||
346 | // KStat is the access handle for the collection of statistics for a | ||
347 | // particular module:instance:name kstat. | ||
348 | // | ||
349 | type KStat struct { | ||
350 | Module string | ||
351 | Instance int | ||
352 | Name string | ||
353 | |||
354 | // Class is eg 'net' or 'disk'. In kstat(1) it shows up as a | ||
355 | // ':class' statistic. | ||
356 | Class string | ||
357 | // Type is the type of kstat. | ||
358 | Type KSType | ||
359 | |||
360 | // Creation time of a kstat in nanoseconds since sometime. | ||
361 | // See gethrtime(3) and kstat(3kstat). | ||
362 | Crtime int64 | ||
363 | // Snaptime is what kstat(1) reports as 'snaptime', the time | ||
364 | // that this data was obtained. As with Crtime, it is in | ||
365 | // nanoseconds since some arbitrary point in time. | ||
366 | // Snaptime may not be valid until .Refresh() or .GetNamed() | ||
367 | // has been called. | ||
368 | Snaptime int64 | ||
369 | |||
370 | ksp *C.struct_kstat | ||
371 | // We need access to the token to refresh the data | ||
372 | tok *Token | ||
373 | } | ||
374 | |||
375 | // newKStat is our internal KStat constructor. | ||
376 | // | ||
377 | // This also has the responsibility of maintaining (and using) the | ||
378 | // kstat_t to KStat mapping cache, so that we don't recreate new | ||
379 | // KStats for the same kstat_t all the time. | ||
380 | func newKStat(tok *Token, ks *C.struct_kstat) *KStat { | ||
381 | if kst, ok := tok.ksm[ks]; ok { | ||
382 | return kst | ||
383 | } | ||
384 | |||
385 | kst := KStat{} | ||
386 | kst.ksp = ks | ||
387 | kst.tok = tok | ||
388 | |||
389 | kst.Instance = int(ks.ks_instance) | ||
390 | kst.Module = strndup((*C.char)(unsafe.Pointer(&ks.ks_module)), C.KSTAT_STRLEN) | ||
391 | kst.Name = strndup((*C.char)(unsafe.Pointer(&ks.ks_name)), C.KSTAT_STRLEN) | ||
392 | kst.Class = strndup((*C.char)(unsafe.Pointer(&ks.ks_class)), C.KSTAT_STRLEN) | ||
393 | kst.Type = KSType(ks.ks_type) | ||
394 | kst.Crtime = int64(ks.ks_crtime) | ||
395 | |||
396 | // Inside the kernel, the ks_snaptime of a kstat is of course | ||
397 | // a global thing. This 'global' snaptime is copied to user | ||
398 | // level as part of the kstat header(s) on kstat_open(), which | ||
399 | // means that kstats that have never been kstat_read() by us | ||
400 | // are almost certain to have a non-zero ks_snaptime (because | ||
401 | // someone, somewhere, will have read them since the system | ||
402 | // booted, eg 'kstat -p | grep ...' reads all kstats). | ||
403 | // Because this ks_snaptime is not useful, we don't copy it | ||
404 | // to Snaptime; instead we leave Snaptime unset (zero) as | ||
405 | // an explicit signal that this KStat has never had its data | ||
406 | // read. | ||
407 | // | ||
408 | //kst.Snaptime = int64(ks.ks_snaptime) | ||
409 | |||
410 | tok.ksm[ks] = &kst | ||
411 | return &kst | ||
412 | } | ||
413 | |||
414 | // invalid is a desperate attempt to keep usage errors from causing | ||
415 | // memory corruption. Don't count on it. | ||
416 | func (k *KStat) invalid() bool { | ||
417 | return k == nil || k.ksp == nil || k.tok == nil || k.tok.kc == nil | ||
418 | } | ||
419 | |||
420 | // setup does validity checks and setup, such as loading data via Refresh(). | ||
421 | // It applies only to named kstats. | ||
422 | // | ||
423 | // TODO: setup() vs prep() is a code smell. | ||
424 | func (k *KStat) setup() error { | ||
425 | if k.invalid() { | ||
426 | return errors.New("invalid KStat or closed token") | ||
427 | } | ||
428 | |||
429 | if k.ksp.ks_type != C.KSTAT_TYPE_NAMED { | ||
430 | return fmt.Errorf("kstat %s (type %d) is not a named kstat", k, k.ksp.ks_type) | ||
431 | } | ||
432 | |||
433 | // Do the initial load of the data if necessary. | ||
434 | if k.ksp.ks_data == nil { | ||
435 | if err := k.Refresh(); err != nil { | ||
436 | return err | ||
437 | } | ||
438 | } | ||
439 | return nil | ||
440 | } | ||
441 | |||
442 | func (k *KStat) String() string { | ||
443 | return fmt.Sprintf("%s:%d:%s (%s)", k.Module, k.Instance, k.Name, k.Class) | ||
444 | } | ||
445 | |||
446 | // Valid returns true if a KStat is still valid after a Token.Update() | ||
447 | // call has returned true. If a KStat becomes invalid after an update, | ||
448 | // its fields remain available but you can no longer call methods on | ||
449 | // it. You may be able to look it up again with token.Lookup(k.Module, | ||
450 | // k.Instance, k.Name), although it's possible that the | ||
451 | // module:instance:name now refers to something else. Even if it is | ||
452 | // still the same thing, there is no continuity in the actual | ||
453 | // statistics once Valid becomes false; you must restart tracking from | ||
454 | // scratch. | ||
455 | // | ||
456 | // (For example, if one disk is removed from the system and another is | ||
457 | // added, the new disk may use the same module:instance:name as some | ||
458 | // of the old disk's KStats. Your .Lookup() may succeed, but what you | ||
459 | // get back is not in any way a continuation of the old disk's | ||
460 | // information.) | ||
461 | // | ||
462 | // Valid also returns false after the KStat's token has been closed. | ||
463 | func (k *KStat) Valid() bool { | ||
464 | return !k.invalid() | ||
465 | } | ||
466 | |||
467 | // Refresh the statistics data for a KStat. | ||
468 | // | ||
469 | // Note that this does not update any existing Named objects for | ||
470 | // statistics from this KStat. You must re-do .GetNamed() to get | ||
471 | // new ones in order to see any updates. | ||
472 | // | ||
473 | // Under the hood this does a kstat_read(). You don't need to call it | ||
474 | // explicitly before obtaining statistics from a KStat. | ||
475 | func (k *KStat) Refresh() error { | ||
476 | if k.invalid() { | ||
477 | return errors.New("invalid KStat or closed token") | ||
478 | } | ||
479 | |||
480 | res, err := C.kstat_read(k.tok.kc, k.ksp, nil) | ||
481 | if res == -1 { | ||
482 | return err | ||
483 | } | ||
484 | k.Snaptime = int64(k.ksp.ks_snaptime) | ||
485 | return nil | ||
486 | } | ||
487 | |||
488 | // GetIO retrieves the IO statistics data from an IoStat type | ||
489 | // KStat. It always refreshes the KStat to provide current data. | ||
490 | // | ||
491 | // It corresponds to kstat_read() followed by getting a copy of | ||
492 | // ks_data (which is a kstat_io_t). | ||
493 | func (k *KStat) GetIO() (*IO, error) { | ||
494 | if err := k.Refresh(); err != nil { | ||
495 | return nil, err | ||
496 | } | ||
497 | if k.ksp.ks_type != C.KSTAT_TYPE_IO { | ||
498 | return nil, fmt.Errorf("kstat %s (type %d) is not an IO kstat", k, k.ksp.ks_type) | ||
499 | } | ||
500 | |||
501 | // We make our own copy of ks_data (as an IO) so that we don't | ||
502 | // point into C-owned memory. 'go tool cgo -godef' apparently | ||
503 | // guarantees that the IO struct/type it creates has exactly | ||
504 | // the same in-memory layout as the C struct, so we can safely | ||
505 | // do this copy and expect to get good results. | ||
506 | io := IO{} | ||
507 | io = *((*IO)(k.ksp.ks_data)) | ||
508 | return &io, nil | ||
509 | } | ||
510 | |||
511 | // GetNamed obtains a particular named statistic from a KStat. It does | ||
512 | // not refresh the KStat's statistics data, so multiple calls to | ||
513 | // GetNamed on a single KStat will get a coherent set of statistic | ||
514 | // values from it. | ||
515 | // | ||
516 | // It corresponds to kstat_data_lookup(). | ||
517 | func (k *KStat) GetNamed(name string) (*Named, error) { | ||
518 | if err := k.setup(); err != nil { | ||
519 | return nil, err | ||
520 | } | ||
521 | ns := C.CString(name) | ||
522 | r, err := C.kstat_data_lookup(k.ksp, ns) | ||
523 | C.free(unsafe.Pointer(ns)) | ||
524 | if r == nil || err != nil { | ||
525 | return nil, err | ||
526 | } | ||
527 | return newNamed(k, (*C.struct_kstat_named)(r)), err | ||
528 | } | ||
529 | |||
530 | // AllNamed returns an array of all named statistics for a particular | ||
531 | // named-type KStat. Entries are returned in no particular order. | ||
532 | func (k *KStat) AllNamed() ([]*Named, error) { | ||
533 | if err := k.setup(); err != nil { | ||
534 | return nil, err | ||
535 | } | ||
536 | lst := make([]*Named, k.ksp.ks_ndata) | ||
537 | for i := C.uint_t(0); i < k.ksp.ks_ndata; i++ { | ||
538 | ks := C.get_nth_named(k.ksp, i) | ||
539 | if ks == nil { | ||
540 | panic("get_nth_named returned surprise nil") | ||
541 | } | ||
542 | lst[i] = newNamed(k, ks) | ||
543 | } | ||
544 | return lst, nil | ||
545 | } | ||
546 | |||
547 | // Named represents a particular kstat named statistic, ie the full | ||
548 | // module:instance:name:statistic | ||
549 | // and its current value. | ||
550 | // | ||
551 | // Name and Type are always valid, but only one of StringVal, IntVal, | ||
552 | // or UintVal is valid for any particular statistic; which one is | ||
553 | // valid is determined by its Type. Generally you'll already know what | ||
554 | // type a given named kstat statistic is; I don't believe Solaris | ||
555 | // changes their type once they're defined. | ||
556 | type Named struct { | ||
557 | Name string | ||
558 | Type NamedType | ||
559 | |||
560 | // Only one of the following values is valid; the others are zero | ||
561 | // values. | ||
562 | // | ||
563 | // StringVal holds the value for both CharData and String Type(s). | ||
564 | StringVal string | ||
565 | IntVal int64 | ||
566 | UintVal uint64 | ||
567 | |||
568 | // The Snaptime this Named was obtained. Note that while you | ||
569 | // use the parent KStat's Crtime, you cannot use its Snaptime. | ||
570 | // The KStat may have been refreshed since this Named was | ||
571 | // created, which updates the Snaptime. | ||
572 | Snaptime int64 | ||
573 | |||
574 | // Pointer to the parent KStat, for access to the full name | ||
575 | // and the crtime associated with this Named. | ||
576 | KStat *KStat | ||
577 | } | ||
578 | |||
579 | func (ks *Named) String() string { | ||
580 | return fmt.Sprintf("%s:%d:%s:%s", ks.KStat.Module, ks.KStat.Instance, ks.KStat.Name, ks.Name) | ||
581 | } | ||
582 | |||
583 | // NamedType represents the various types of named kstat statistics. | ||
584 | type NamedType int | ||
585 | |||
586 | // The different types of data that a named kstat statistic can be | ||
587 | // (ie, these are the potential values of Named.Type). | ||
588 | const ( | ||
589 | CharData NamedType = C.KSTAT_DATA_CHAR | ||
590 | Int32 NamedType = C.KSTAT_DATA_INT32 | ||
591 | Uint32 NamedType = C.KSTAT_DATA_UINT32 | ||
592 | Int64 NamedType = C.KSTAT_DATA_INT64 | ||
593 | Uint64 NamedType = C.KSTAT_DATA_UINT64 | ||
594 | String NamedType = C.KSTAT_DATA_STRING | ||
595 | |||
596 | // CharData is found in StringVal. At the moment we assume that | ||
597 | // it is a real string, because this matches how it seems to be | ||
598 | // used for short strings in the Solaris kernel. Someday we may | ||
599 | // find something that uses it as just a data dump for 16 bytes. | ||
600 | |||
601 | // Solaris sys/kstat.h also has _FLOAT (5) and _DOUBLE (6) types, | ||
602 | // but labels them as obsolete. | ||
603 | ) | ||
604 | |||
605 | func (tp NamedType) String() string { | ||
606 | switch tp { | ||
607 | case CharData: | ||
608 | return "char" | ||
609 | case Int32: | ||
610 | return "int32" | ||
611 | case Uint32: | ||
612 | return "uint32" | ||
613 | case Int64: | ||
614 | return "int64" | ||
615 | case Uint64: | ||
616 | return "uint64" | ||
617 | case String: | ||
618 | return "string" | ||
619 | default: | ||
620 | return fmt.Sprintf("named_type-%d", tp) | ||
621 | } | ||
622 | } | ||
623 | |||
624 | // Create a new Stat from the kstat_named_t | ||
625 | // We set the appropriate *Value field. | ||
626 | func newNamed(k *KStat, knp *C.struct_kstat_named) *Named { | ||
627 | st := Named{} | ||
628 | st.KStat = k | ||
629 | st.Name = strndup((*C.char)(unsafe.Pointer(&knp.name)), C.KSTAT_STRLEN) | ||
630 | st.Type = NamedType(knp.data_type) | ||
631 | st.Snaptime = k.Snaptime | ||
632 | |||
633 | switch st.Type { | ||
634 | case String: | ||
635 | // The comments in sys/kstat.h explicitly guarantee | ||
636 | // that these strings are null-terminated, although | ||
637 | // knp.value.str.len also holds the length. | ||
638 | st.StringVal = C.GoString(C.get_named_char(knp)) | ||
639 | case CharData: | ||
640 | // Solaris/etc appears to use CharData for short strings | ||
641 | // so that they can be embedded directly into | ||
642 | // knp.value.c[16] instead of requiring an out of line | ||
643 | // allocation. In theory we may find someone who is | ||
644 | // using it as 128-bit ints or the like. | ||
645 | // However I scanned the Illumos kernel source and | ||
646 | // everyone using it appears to really be using it for | ||
647 | // strings. | ||
648 | st.StringVal = strndup((*C.char)(unsafe.Pointer(&knp.value)), 16) | ||
649 | case Int32, Int64: | ||
650 | st.IntVal = int64(C.get_named_int(knp)) | ||
651 | case Uint32, Uint64: | ||
652 | st.UintVal = uint64(C.get_named_uint(knp)) | ||
653 | default: | ||
654 | // TODO: should do better. | ||
655 | panic(fmt.Sprintf("unknown stat type: %d", st.Type)) | ||
656 | } | ||
657 | return &st | ||
658 | } | ||
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 0000000..98d7118 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/raw_solaris.go | |||
@@ -0,0 +1,236 @@ | |||
1 | // | ||
2 | // Really raw access to KStat data | ||
3 | |||
4 | package kstat | ||
5 | |||
6 | // #cgo LDFLAGS: -lkstat | ||
7 | // | ||
8 | // #include <sys/types.h> | ||
9 | // #include <stdlib.h> | ||
10 | // #include <strings.h> | ||
11 | // #include <kstat.h> | ||
12 | // #include <nfs/nfs_clnt.h> | ||
13 | // | ||
14 | import "C" | ||
15 | import ( | ||
16 | "errors" | ||
17 | "fmt" | ||
18 | "reflect" | ||
19 | "unsafe" | ||
20 | ) | ||
21 | |||
22 | // Raw is the raw data of a KStat. The actual bytes are in Data; | ||
23 | // Ndata is kstat_t.ks_ndata, and is not normally useful. | ||
24 | // | ||
25 | // Note that with RawStat KStats, it turns out that Ndata == len(Data). | ||
26 | // This is contrary to its meaning for other types of kstats. | ||
27 | type Raw struct { | ||
28 | Data []byte | ||
29 | Ndata uint64 | ||
30 | Snaptime int64 | ||
31 | KStat *KStat | ||
32 | } | ||
33 | |||
34 | // TODO: better functionality split here | ||
35 | func (k *KStat) prep() error { | ||
36 | if k.invalid() { | ||
37 | return errors.New("invalid KStat or closed token") | ||
38 | } | ||
39 | |||
40 | // Do the initial load of the data if necessary. | ||
41 | if k.ksp.ks_data == nil { | ||
42 | if err := k.Refresh(); err != nil { | ||
43 | return err | ||
44 | } | ||
45 | } | ||
46 | return nil | ||
47 | } | ||
48 | |||
49 | // Raw returns the raw byte data of a KStat. It may be called on any | ||
50 | // KStat. It does not refresh the KStat's data. | ||
51 | func (k *KStat) Raw() (*Raw, error) { | ||
52 | if err := k.prep(); err != nil { | ||
53 | return nil, err | ||
54 | } | ||
55 | r := Raw{} | ||
56 | r.KStat = k | ||
57 | r.Snaptime = k.Snaptime | ||
58 | r.Ndata = uint64(k.ksp.ks_ndata) | ||
59 | // The forced C.int() conversion is dangerous, because C.int | ||
60 | // is not necessarily large enough to contain a | ||
61 | // size_t. However this is the interface that Go gives us, so | ||
62 | // we live with it. | ||
63 | r.Data = C.GoBytes(unsafe.Pointer(k.ksp.ks_data), C.int(k.ksp.ks_data_size)) | ||
64 | return &r, nil | ||
65 | } | ||
66 | |||
67 | func (tok *Token) prepunix(name string, size uintptr) (*KStat, error) { | ||
68 | k, err := tok.Lookup("unix", 0, name) | ||
69 | if err != nil { | ||
70 | return nil, err | ||
71 | } | ||
72 | // TODO: handle better? | ||
73 | if k.ksp.ks_type != C.KSTAT_TYPE_RAW { | ||
74 | return nil, fmt.Errorf("%s is wrong type %s", k, k.Type) | ||
75 | } | ||
76 | if uintptr(k.ksp.ks_data_size) != size { | ||
77 | return nil, fmt.Errorf("%s is wrong size %d (should be %d)", k, k.ksp.ks_data_size, size) | ||
78 | } | ||
79 | return k, nil | ||
80 | } | ||
81 | |||
82 | // Sysinfo returns the KStat and the statistics from unix:0:sysinfo. | ||
83 | // It always returns a current, refreshed copy. | ||
84 | func (tok *Token) Sysinfo() (*KStat, *Sysinfo, error) { | ||
85 | var si Sysinfo | ||
86 | k, err := tok.prepunix("sysinfo", unsafe.Sizeof(si)) | ||
87 | if err != nil { | ||
88 | return nil, nil, err | ||
89 | } | ||
90 | si = *((*Sysinfo)(k.ksp.ks_data)) | ||
91 | return k, &si, nil | ||
92 | } | ||
93 | |||
94 | // Vminfo returns the KStat and the statistics from unix:0:vminfo. | ||
95 | // It always returns a current, refreshed copy. | ||
96 | func (tok *Token) Vminfo() (*KStat, *Vminfo, error) { | ||
97 | var vi Vminfo | ||
98 | k, err := tok.prepunix("vminfo", unsafe.Sizeof(vi)) | ||
99 | if err != nil { | ||
100 | return nil, nil, err | ||
101 | } | ||
102 | vi = *((*Vminfo)(k.ksp.ks_data)) | ||
103 | return k, &vi, nil | ||
104 | } | ||
105 | |||
106 | // Var returns the KStat and the statistics from unix:0:var. | ||
107 | // It always returns a current, refreshed copy. | ||
108 | func (tok *Token) Var() (*KStat, *Var, error) { | ||
109 | var vi Var | ||
110 | k, err := tok.prepunix("var", unsafe.Sizeof(vi)) | ||
111 | if err != nil { | ||
112 | return nil, nil, err | ||
113 | } | ||
114 | vi = *((*Var)(k.ksp.ks_data)) | ||
115 | return k, &vi, nil | ||
116 | } | ||
117 | |||
118 | // GetMntinfo retrieves a Mntinfo struct from a nfs:*:mntinfo KStat. | ||
119 | // It does not force a refresh of the KStat. | ||
120 | func (k *KStat) GetMntinfo() (*Mntinfo, error) { | ||
121 | var mi Mntinfo | ||
122 | if err := k.prep(); err != nil { | ||
123 | return nil, err | ||
124 | } | ||
125 | if k.Type != RawStat || k.Module != "nfs" || k.Name != "mntinfo" { | ||
126 | return nil, errors.New("KStat is not a Mntinfo kstat") | ||
127 | } | ||
128 | if uintptr(k.ksp.ks_data_size) != unsafe.Sizeof(mi) { | ||
129 | return nil, fmt.Errorf("KStat is wrong size %d (should be %d)", k.ksp.ks_data_size, unsafe.Sizeof(mi)) | ||
130 | } | ||
131 | mi = *((*Mntinfo)(k.ksp.ks_data)) | ||
132 | return &mi, nil | ||
133 | } | ||
134 | |||
135 | // | ||
136 | // Support for copying semi-arbitrary structures out of raw | ||
137 | // KStats. | ||
138 | // | ||
139 | |||
140 | // safeThing returns true if a given type is either a simple defined | ||
141 | // size primitive integer type or an array and/or struct composed | ||
142 | // entirely of safe things. A safe thing is entirely self contained | ||
143 | // and may be initialized from random memory without breaking Go's | ||
144 | // memory safety (although the values it contains may be garbage). | ||
145 | // | ||
146 | func safeThing(t reflect.Type) bool { | ||
147 | switch t.Kind() { | ||
148 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
149 | return true | ||
150 | case reflect.Array: | ||
151 | // an array is safe if it's an array of something safe | ||
152 | return safeThing(t.Elem()) | ||
153 | case reflect.Struct: | ||
154 | // a struct is safe if all its components are safe | ||
155 | for i := 0; i < t.NumField(); i++ { | ||
156 | if !safeThing(t.Field(i).Type) { | ||
157 | return false | ||
158 | } | ||
159 | } | ||
160 | return true | ||
161 | default: | ||
162 | // other things are not safe. | ||
163 | return false | ||
164 | } | ||
165 | } | ||
166 | |||
167 | // TODO: add floats to the supported list? It's unlikely to be needed | ||
168 | // but it should just work. | ||
169 | |||
170 | // CopyTo copies a RawStat KStat into a struct that you supply a | ||
171 | // pointer to. The size of the struct must exactly match the size of | ||
172 | // the RawStat's data. | ||
173 | // | ||
174 | // CopyStat imposes conditions on the struct that you are copying to: | ||
175 | // it must be composed entirely of primitive integer types with defined | ||
176 | // sizes (intN and uintN), or arrays and structs that ultimately only | ||
177 | // contain them. All fields should be exported. | ||
178 | // | ||
179 | // If you give CopyStat a bad argument, it generally panics. | ||
180 | // | ||
181 | // This API is provisional and may be changed or deleted. | ||
182 | func (k *KStat) CopyTo(ptr interface{}) error { | ||
183 | if err := k.prep(); err != nil { | ||
184 | return err | ||
185 | } | ||
186 | |||
187 | if k.Type != RawStat { | ||
188 | return errors.New("KStat is not a RawStat") | ||
189 | } | ||
190 | |||
191 | // Validity checks: not nil value, not nil pointer value, | ||
192 | // is a pointer to struct. | ||
193 | if ptr == nil { | ||
194 | panic("CopyTo given nil pointer") | ||
195 | } | ||
196 | vp := reflect.ValueOf(ptr) | ||
197 | if vp.Kind() != reflect.Ptr { | ||
198 | panic("CopyTo not given a pointer") | ||
199 | } | ||
200 | if vp.IsNil() { | ||
201 | panic("CopyTo given nil pointer") | ||
202 | } | ||
203 | dst := vp.Elem() | ||
204 | if dst.Kind() != reflect.Struct { | ||
205 | panic("CopyTo: not pointer to struct") | ||
206 | } | ||
207 | // Is the struct safe to copy into, which means primitive types | ||
208 | // and structs/arrays of primitive types? | ||
209 | if !safeThing(dst.Type()) { | ||
210 | panic("CopyTo: not a safe structure, contains unsupported fields") | ||
211 | } | ||
212 | if !dst.CanSet() { | ||
213 | panic("CopyTo: struct cannot be set for some reason") | ||
214 | } | ||
215 | |||
216 | // Verify that the size of the target struct matches the size | ||
217 | // of the raw KStat. | ||
218 | if uintptr(k.ksp.ks_data_size) != dst.Type().Size() { | ||
219 | return errors.New("struct size does not match KStat size") | ||
220 | } | ||
221 | |||
222 | // The following is exactly the magic that we performed for | ||
223 | // specific types earlier. We take k.ksp.ks_data and turn | ||
224 | // it into a typed pointer to the target object's type: | ||
225 | // | ||
226 | // src := ((*<type>)(k.kps.ks_data)) | ||
227 | src := reflect.NewAt(dst.Type(), unsafe.Pointer(k.ksp.ks_data)) | ||
228 | |||
229 | // We now dereference that into the destination to copy the | ||
230 | // data: | ||
231 | // | ||
232 | // dst = *src | ||
233 | dst.Set(reflect.Indirect(src)) | ||
234 | |||
235 | return nil | ||
236 | } | ||
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 0000000..bea0960 --- /dev/null +++ b/vendor/github.com/siebenmann/go-kstat/types_solaris_amd64.go | |||
@@ -0,0 +1,141 @@ | |||
1 | // | ||
2 | // Initially created by | ||
3 | // cgo -godefs ctypes_solaris.go | ||
4 | // | ||
5 | // Now contains edits for documentation. This is considered okay by me | ||
6 | // because these structs are not exactly likely to change any time | ||
7 | // soon; that would break API compatibility. | ||
8 | // | ||
9 | // This is specific to amd64. It's unlikely that Go will support | ||
10 | // 32-bit Solaris ('386'), but. | ||
11 | |||
12 | package kstat | ||
13 | |||
14 | // IO represents the entire collection of KStat (disk) IO statistics | ||
15 | // exposed by an IoStat type KStat. | ||
16 | // | ||
17 | // Because IO is an exact copy of the C kstat_io_t structure from the | ||
18 | // kernel, it does not have a Snaptime or KStat field. You must save | ||
19 | // that information separately if you need it, perhaps by embedded the | ||
20 | // IO struct as an anonymous struct in an additional struct of your | ||
21 | // own. | ||
22 | type IO struct { | ||
23 | Nread uint64 | ||
24 | Nwritten uint64 | ||
25 | Reads uint32 | ||
26 | Writes uint32 | ||
27 | Wtime int64 | ||
28 | Wlentime int64 | ||
29 | Wlastupdate int64 | ||
30 | Rtime int64 | ||
31 | Rlentime int64 | ||
32 | Rlastupdate int64 | ||
33 | Wcnt uint32 | ||
34 | Rcnt uint32 | ||
35 | } | ||
36 | |||
37 | // Sysinfo is the data from unix:0:sysinfo, which is a sysinfo_t. | ||
38 | type Sysinfo struct { | ||
39 | Updates uint32 | ||
40 | Runque uint32 | ||
41 | Runocc uint32 | ||
42 | Swpque uint32 | ||
43 | Swpocc uint32 | ||
44 | Waiting uint32 | ||
45 | } | ||
46 | |||
47 | // Vminfo is the data from unix:0:vminfo, which is a vminfo_t. | ||
48 | type Vminfo struct { | ||
49 | Freemem uint64 | ||
50 | Resv uint64 | ||
51 | Alloc uint64 | ||
52 | Avail uint64 | ||
53 | Free uint64 | ||
54 | Updates uint64 | ||
55 | } | ||
56 | |||
57 | // Var is the data from unix:0:var, which is a 'struct var'. | ||
58 | type Var struct { | ||
59 | Buf int32 | ||
60 | Call int32 | ||
61 | Proc int32 | ||
62 | Maxupttl int32 | ||
63 | Nglobpris int32 | ||
64 | Maxsyspri int32 | ||
65 | Clist int32 | ||
66 | Maxup int32 | ||
67 | Hbuf int32 | ||
68 | Hmask int32 | ||
69 | Pbuf int32 | ||
70 | Sptmap int32 | ||
71 | Maxpmem int32 | ||
72 | Autoup int32 | ||
73 | Bufhwm int32 | ||
74 | } | ||
75 | |||
76 | // Mntinfo is the kernel data from nfs:*:mntinfo, which is a 'struct | ||
77 | // mntinfo_kstat'. Use .Proto() and .Curserver() to get the RProto | ||
78 | // and RCurserver fields as strings instead of their awkward raw form. | ||
79 | type Mntinfo struct { | ||
80 | RProto [128]int8 | ||
81 | Vers uint32 | ||
82 | Flags uint32 | ||
83 | Secmod uint32 | ||
84 | Curread uint32 | ||
85 | Curwrite uint32 | ||
86 | Timeo int32 | ||
87 | Retrans int32 | ||
88 | Acregmin uint32 | ||
89 | Acregmax uint32 | ||
90 | Acdirmin uint32 | ||
91 | Acdirmax uint32 | ||
92 | Timers [4]struct { | ||
93 | Srtt uint32 | ||
94 | Deviate uint32 | ||
95 | Rtxcur uint32 | ||
96 | } | ||
97 | Noresponse uint32 | ||
98 | Failover uint32 | ||
99 | Remap uint32 | ||
100 | RCurserver [257]int8 | ||
101 | pad0 [3]byte | ||
102 | } | ||
103 | |||
104 | // CFieldString converts a (null-terminated) C string embedded in an | ||
105 | // []int8 slice to a (Go) string. The []int8 slice is likely to come | ||
106 | // from an [N]int8 fixed-size field in a statistics struct. If there | ||
107 | // is no null in the slice, the entire slice is returned. | ||
108 | // | ||
109 | // (The no-null behavior is common in C APIs; a string is often allowed | ||
110 | // to exactly fill the field with no room for a trailing null.) | ||
111 | func CFieldString(src []int8) string { | ||
112 | slen := len(src) | ||
113 | buf := make([]byte, slen) | ||
114 | for i := 0; i < len(src); i++ { | ||
115 | buf[i] = byte(src[i]) | ||
116 | if src[i] == 0 { | ||
117 | slen = i | ||
118 | break | ||
119 | } | ||
120 | } | ||
121 | return string(buf[:slen]) | ||
122 | } | ||
123 | |||
124 | // Proto returns a Mntinfo RProto as a string. | ||
125 | func (m Mntinfo) Proto() string { | ||
126 | return CFieldString(m.RProto[:]) | ||
127 | } | ||
128 | |||
129 | // Curserver returns a Mntinfo RCurserver as a string. | ||
130 | func (m Mntinfo) Curserver() string { | ||
131 | return CFieldString(m.RCurserver[:]) | ||
132 | } | ||
133 | |||
134 | // The Mntinfo type is not an exact conversion as produced by cgo; | ||
135 | // because the original struct mntinfo_kstat contains an embedded | ||
136 | // anonymously typed struct, it runs into | ||
137 | // https://github.com/golang/go/issues/5253. This version is manually | ||
138 | // produced from a cgo starting point and then verified to be the same | ||
139 | // size. | ||
140 | // It also has Proto and Curserver renamed so we can add methods to | ||
141 | // get them as Go strings. | ||
diff --git a/vendor/modules.txt b/vendor/modules.txt index dbd7d5f..25bff14 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt | |||
@@ -43,7 +43,7 @@ github.com/prometheus/common/version | |||
43 | github.com/prometheus/common/expfmt | 43 | github.com/prometheus/common/expfmt |
44 | github.com/prometheus/common/model | 44 | github.com/prometheus/common/model |
45 | github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg | 45 | github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg |
46 | # github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d | 46 | # github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5 |
47 | github.com/prometheus/procfs | 47 | github.com/prometheus/procfs |
48 | github.com/prometheus/procfs/bcache | 48 | github.com/prometheus/procfs/bcache |
49 | github.com/prometheus/procfs/nfs | 49 | github.com/prometheus/procfs/nfs |