update procfs to latest (#1335)

Updates for procfs refactoring

Signed-off-by: Paul Gier <pgier@redhat.com>
This commit is contained in:
Paul Gier 2019-05-06 23:38:21 -05:00 committed by Ben Kochie
parent c7abeae816
commit 86f9079429
33 changed files with 1964 additions and 1380 deletions

View file

@ -21,7 +21,6 @@ import (
// https://godoc.org/github.com/prometheus/client_golang/prometheus // https://godoc.org/github.com/prometheus/client_golang/prometheus
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs/bcache" "github.com/prometheus/procfs/bcache"
"github.com/prometheus/procfs/sysfs"
) )
func init() { func init() {
@ -30,13 +29,13 @@ func init() {
// A bcacheCollector is a Collector which gathers metrics from Linux bcache. // A bcacheCollector is a Collector which gathers metrics from Linux bcache.
type bcacheCollector struct { type bcacheCollector struct {
fs sysfs.FS fs bcache.FS
} }
// NewBcacheCollector returns a newly allocated bcacheCollector. // NewBcacheCollector returns a newly allocated bcacheCollector.
// It exposes a number of Linux bcache statistics. // It exposes a number of Linux bcache statistics.
func NewBcacheCollector() (Collector, error) { func NewBcacheCollector() (Collector, error) {
fs, err := sysfs.NewFS(*sysPath) fs, err := bcache.NewFS(*sysPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open sysfs: %v", err) return nil, fmt.Errorf("failed to open sysfs: %v", err)
} }
@ -49,7 +48,7 @@ func NewBcacheCollector() (Collector, error) {
// Update reads and exposes bcache stats. // Update reads and exposes bcache stats.
// It implements the Collector interface. // It implements the Collector interface.
func (c *bcacheCollector) Update(ch chan<- prometheus.Metric) error { func (c *bcacheCollector) Update(ch chan<- prometheus.Metric) error {
stats, err := c.fs.BcacheStats() stats, err := c.fs.Stats()
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve bcache stats: %v", err) return fmt.Errorf("failed to retrieve bcache stats: %v", err)
} }

View file

@ -20,7 +20,6 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log" "github.com/prometheus/common/log"
"github.com/prometheus/procfs"
"github.com/prometheus/procfs/nfs" "github.com/prometheus/procfs/nfs"
) )
@ -29,7 +28,7 @@ const (
) )
type nfsCollector struct { type nfsCollector struct {
fs procfs.FS fs nfs.FS
nfsNetReadsDesc *prometheus.Desc nfsNetReadsDesc *prometheus.Desc
nfsNetConnectionsDesc *prometheus.Desc nfsNetConnectionsDesc *prometheus.Desc
nfsRPCOperationsDesc *prometheus.Desc nfsRPCOperationsDesc *prometheus.Desc
@ -44,7 +43,7 @@ func init() {
// NewNfsCollector returns a new Collector exposing NFS statistics. // NewNfsCollector returns a new Collector exposing NFS statistics.
func NewNfsCollector() (Collector, error) { func NewNfsCollector() (Collector, error) {
fs, err := procfs.NewFS(*procPath) fs, err := nfs.NewFS(*procPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open procfs: %v", err) return nil, fmt.Errorf("failed to open procfs: %v", err)
} }
@ -91,7 +90,7 @@ func NewNfsCollector() (Collector, error) {
} }
func (c *nfsCollector) Update(ch chan<- prometheus.Metric) error { func (c *nfsCollector) Update(ch chan<- prometheus.Metric) error {
stats, err := c.fs.NFSClientRPCStats() stats, err := c.fs.ClientRPCStats()
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
log.Debugf("Not collecting NFS metrics: %s", err) log.Debugf("Not collecting NFS metrics: %s", err)

View file

@ -19,14 +19,13 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log" "github.com/prometheus/common/log"
"github.com/prometheus/procfs"
"github.com/prometheus/procfs/nfs" "github.com/prometheus/procfs/nfs"
) )
// A nfsdCollector is a Collector which gathers metrics from /proc/net/rpc/nfsd. // A nfsdCollector is a Collector which gathers metrics from /proc/net/rpc/nfsd.
// See: https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/ // See: https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/
type nfsdCollector struct { type nfsdCollector struct {
fs procfs.FS fs nfs.FS
requestsDesc *prometheus.Desc requestsDesc *prometheus.Desc
} }
@ -40,7 +39,7 @@ const (
// NewNFSdCollector returns a new Collector exposing /proc/net/rpc/nfsd statistics. // NewNFSdCollector returns a new Collector exposing /proc/net/rpc/nfsd statistics.
func NewNFSdCollector() (Collector, error) { func NewNFSdCollector() (Collector, error) {
fs, err := procfs.NewFS(*procPath) fs, err := nfs.NewFS(*procPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open procfs: %v", err) return nil, fmt.Errorf("failed to open procfs: %v", err)
} }
@ -57,7 +56,7 @@ func NewNFSdCollector() (Collector, error) {
// Update implements Collector. // Update implements Collector.
func (c *nfsdCollector) Update(ch chan<- prometheus.Metric) error { func (c *nfsdCollector) Update(ch chan<- prometheus.Metric) error {
stats, err := c.fs.NFSdServerRPCStats() stats, err := c.fs.ServerRPCStats()
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
log.Debugf("Not collecting NFSd metrics: %s", err) log.Debugf("Not collecting NFSd metrics: %s", err)

View file

@ -17,13 +17,12 @@ import (
"fmt" "fmt"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs/sysfs"
"github.com/prometheus/procfs/xfs" "github.com/prometheus/procfs/xfs"
) )
// An xfsCollector is a Collector which gathers metrics from XFS filesystems. // An xfsCollector is a Collector which gathers metrics from XFS filesystems.
type xfsCollector struct { type xfsCollector struct {
fs sysfs.FS fs xfs.FS
} }
func init() { func init() {
@ -32,7 +31,7 @@ func init() {
// NewXFSCollector returns a new Collector exposing XFS statistics. // NewXFSCollector returns a new Collector exposing XFS statistics.
func NewXFSCollector() (Collector, error) { func NewXFSCollector() (Collector, error) {
fs, err := sysfs.NewFS(*sysPath) fs, err := xfs.NewFS(*procPath, *sysPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open sysfs: %v", err) return nil, fmt.Errorf("failed to open sysfs: %v", err)
} }
@ -44,7 +43,7 @@ func NewXFSCollector() (Collector, error) {
// Update implements Collector. // Update implements Collector.
func (c *xfsCollector) Update(ch chan<- prometheus.Metric) error { func (c *xfsCollector) Update(ch chan<- prometheus.Metric) error {
stats, err := c.fs.XFSStats() stats, err := c.fs.SysStats()
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve XFS stats: %v", err) return fmt.Errorf("failed to retrieve XFS stats: %v", err)
} }

4
go.mod
View file

@ -16,13 +16,13 @@ require (
github.com/prometheus/client_golang v0.9.2 github.com/prometheus/client_golang v0.9.2
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
github.com/prometheus/common v0.2.0 github.com/prometheus/common v0.2.0
github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd github.com/prometheus/procfs v0.0.0-20190503130316-740c07785007
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745
github.com/sirupsen/logrus v1.4.1 // indirect github.com/sirupsen/logrus v1.4.1 // indirect
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
github.com/stretchr/testify v1.3.0 // indirect github.com/stretchr/testify v1.3.0 // indirect
golang.org/x/net v0.0.0-20190328230028-74de082e2cca // indirect golang.org/x/net v0.0.0-20190328230028-74de082e2cca // indirect
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
golang.org/x/sys v0.0.0-20190402142545-baf5eb976a8c golang.org/x/sys v0.0.0-20190402142545-baf5eb976a8c
gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/alecthomas/kingpin.v2 v2.2.6
) )

8
go.sum
View file

@ -61,8 +61,8 @@ github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVw
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd h1:pi7bGw6n4tfgHQtWDxJBBLYVdFr1GlfQEsDOyCDDFMM= github.com/prometheus/procfs v0.0.0-20190503130316-740c07785007 h1:gT4PpkbWSQM4J8fup/aXeQhY5jLDyHuPq8y2dHspqFw=
github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190503130316-740c07785007/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 h1:IuH7WumZNax0D+rEqmy2TyhKCzrtMGqbZO0b8rO00JA= github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 h1:IuH7WumZNax0D+rEqmy2TyhKCzrtMGqbZO0b8rO00JA=
github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8= github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@ -86,8 +86,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTm
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

6
vendor/github.com/prometheus/procfs/.golangci.yml generated vendored Normal file
View file

@ -0,0 +1,6 @@
# Run only staticcheck for now. Additional linters will be enabled one-by-one.
linters:
enable:
- staticcheck
- govet
disable-all: true

View file

@ -17,14 +17,12 @@ include Makefile.common
./ttar -C $(dir $*) -x -f $*.ttar ./ttar -C $(dir $*) -x -f $*.ttar
touch $@ touch $@
update_fixtures: fixtures.ttar sysfs/fixtures.ttar update_fixtures:
rm -vf fixtures/.unpacked
%fixtures.ttar: %/fixtures ./ttar -c -f fixtures.ttar fixtures/
rm -v $(dir $*)fixtures/.unpacked
./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/
.PHONY: build .PHONY: build
build: build:
.PHONY: test .PHONY: test
test: fixtures/.unpacked sysfs/fixtures/.unpacked common-test test: fixtures/.unpacked common-test

View file

@ -29,12 +29,15 @@ GO ?= go
GOFMT ?= $(GO)fmt GOFMT ?= $(GO)fmt
FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH)))
GOOPTS ?= GOOPTS ?=
GOHOSTOS ?= $(shell $(GO) env GOHOSTOS)
GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH)
GO_VERSION ?= $(shell $(GO) version) GO_VERSION ?= $(shell $(GO) version)
GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))
PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.')
unexport GOVENDOR GOVENDOR :=
GO111MODULE :=
ifeq (, $(PRE_GO_111)) ifeq (, $(PRE_GO_111))
ifneq (,$(wildcard go.mod)) ifneq (,$(wildcard go.mod))
# Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI).
@ -55,32 +58,56 @@ $(warning Some recipes may not work as expected as the current Go runtime is '$(
# This repository isn't using Go modules (yet). # This repository isn't using Go modules (yet).
GOVENDOR := $(FIRST_GOPATH)/bin/govendor GOVENDOR := $(FIRST_GOPATH)/bin/govendor
endif endif
unexport GO111MODULE
endif endif
PROMU := $(FIRST_GOPATH)/bin/promu PROMU := $(FIRST_GOPATH)/bin/promu
STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck
pkgs = ./... pkgs = ./...
GO_VERSION ?= $(shell $(GO) version) ifeq (arm, $(GOHOSTARCH))
GO_BUILD_PLATFORM ?= $(subst /,-,$(lastword $(GO_VERSION))) GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM)
GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM)
else
GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)
endif
PROMU_VERSION ?= 0.2.0 PROMU_VERSION ?= 0.3.0
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
GOLANGCI_LINT :=
GOLANGCI_LINT_VERSION ?= v1.16.0
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386))
GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
endif
endif
PREFIX ?= $(shell pwd) PREFIX ?= $(shell pwd)
BIN_DIR ?= $(shell pwd) BIN_DIR ?= $(shell pwd)
DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
DOCKER_REPO ?= prom DOCKER_REPO ?= prom
.PHONY: all DOCKER_ARCHS ?= amd64
all: precheck style staticcheck unused build test
BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS))
PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS))
TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS))
ifeq ($(GOHOSTARCH),amd64)
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows))
# Only supported on amd64
test-flags := -race
endif
endif
# This rule is used to forward a target like "build" to "common-build". This # This rule is used to forward a target like "build" to "common-build". This
# allows a new "build" target to be defined in a Makefile which includes this # allows a new "build" target to be defined in a Makefile which includes this
# one and override "common-build" without override warnings. # one and override "common-build" without override warnings.
%: common-% ; %: common-% ;
.PHONY: common-all
common-all: precheck style check_license lint unused build test
.PHONY: common-style .PHONY: common-style
common-style: common-style:
@echo ">> checking code style" @echo ">> checking code style"
@ -102,6 +129,15 @@ common-check_license:
exit 1; \ exit 1; \
fi fi
.PHONY: common-deps
common-deps:
@echo ">> getting dependencies"
ifdef GO111MODULE
GO111MODULE=$(GO111MODULE) $(GO) mod download
else
$(GO) get $(GOOPTS) -t ./...
endif
.PHONY: common-test-short .PHONY: common-test-short
common-test-short: common-test-short:
@echo ">> running short tests" @echo ">> running short tests"
@ -110,26 +146,35 @@ common-test-short:
.PHONY: common-test .PHONY: common-test
common-test: common-test:
@echo ">> running all tests" @echo ">> running all tests"
GO111MODULE=$(GO111MODULE) $(GO) test -race $(GOOPTS) $(pkgs) GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs)
.PHONY: common-format .PHONY: common-format
common-format: common-format:
@echo ">> formatting code" @echo ">> formatting code"
GO111MODULE=$(GO111MODULE) $(GO) fmt $(GOOPTS) $(pkgs) GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs)
.PHONY: common-vet .PHONY: common-vet
common-vet: common-vet:
@echo ">> vetting code" @echo ">> vetting code"
GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs)
.PHONY: common-staticcheck .PHONY: common-lint
common-staticcheck: $(STATICCHECK) common-lint: $(GOLANGCI_LINT)
@echo ">> running staticcheck" ifdef GOLANGCI_LINT
@echo ">> running golangci-lint"
ifdef GO111MODULE ifdef GO111MODULE
GO111MODULE=$(GO111MODULE) $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" -checks "SA*" $(pkgs) # 'go list' needs to be executed before staticcheck to prepopulate the modules cache.
# Otherwise staticcheck might fail randomly for some reason not yet explained.
GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null
GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(pkgs)
else else
$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) $(GOLANGCI_LINT) run $(pkgs)
endif endif
endif
# For backward-compatibility.
.PHONY: common-staticcheck
common-staticcheck: lint
.PHONY: common-unused .PHONY: common-unused
common-unused: $(GOVENDOR) common-unused: $(GOVENDOR)
@ -140,8 +185,9 @@ else
ifdef GO111MODULE ifdef GO111MODULE
@echo ">> running check for unused/missing packages in go.mod" @echo ">> running check for unused/missing packages in go.mod"
GO111MODULE=$(GO111MODULE) $(GO) mod tidy GO111MODULE=$(GO111MODULE) $(GO) mod tidy
ifeq (,$(wildcard vendor))
@git diff --exit-code -- go.sum go.mod @git diff --exit-code -- go.sum go.mod
ifneq (,$(wildcard vendor)) else
@echo ">> running check for unused packages in vendor/" @echo ">> running check for unused packages in vendor/"
GO111MODULE=$(GO111MODULE) $(GO) mod vendor GO111MODULE=$(GO111MODULE) $(GO) mod vendor
@git diff --exit-code -- go.sum go.mod vendor/ @git diff --exit-code -- go.sum go.mod vendor/
@ -159,45 +205,48 @@ common-tarball: promu
@echo ">> building release tarball" @echo ">> building release tarball"
$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR)
.PHONY: common-docker .PHONY: common-docker $(BUILD_DOCKER_ARCHS)
common-docker: common-docker: $(BUILD_DOCKER_ARCHS)
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" . $(BUILD_DOCKER_ARCHS): common-docker-%:
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \
--build-arg ARCH="$*" \
--build-arg OS="linux" \
.
.PHONY: common-docker-publish .PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
common-docker-publish: common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" $(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
.PHONY: common-docker-tag-latest .PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
common-docker-tag-latest: common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):latest" $(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
.PHONY: common-docker-manifest
common-docker-manifest:
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG))
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)"
.PHONY: promu .PHONY: promu
promu: $(PROMU) promu: $(PROMU)
$(PROMU): $(PROMU):
curl -s -L $(PROMU_URL) | tar -xvz -C /tmp $(eval PROMU_TMP := $(shell mktemp -d))
mkdir -v -p $(FIRST_GOPATH)/bin curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP)
cp -v /tmp/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(PROMU) mkdir -p $(FIRST_GOPATH)/bin
cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
rm -r $(PROMU_TMP)
.PHONY: proto .PHONY: proto
proto: proto:
@echo ">> generating code from proto files" @echo ">> generating code from proto files"
@./scripts/genproto.sh @./scripts/genproto.sh
.PHONY: $(STATICCHECK) ifdef GOLANGCI_LINT
$(STATICCHECK): $(GOLANGCI_LINT):
ifdef GO111MODULE mkdir -p $(FIRST_GOPATH)/bin
# Get staticcheck from a temporary directory to avoid modifying the local go.{mod,sum}. curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
# See https://github.com/golang/go/issues/27643.
# For now, we are using the next branch of staticcheck because master isn't compatible yet with Go modules.
tmpModule=$$(mktemp -d 2>&1) && \
mkdir -p $${tmpModule}/staticcheck && \
cd "$${tmpModule}"/staticcheck && \
GO111MODULE=on $(GO) mod init example.com/staticcheck && \
GO111MODULE=on GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck@next && \
rm -rf $${tmpModule};
else
GOOS= GOARCH= GO111MODULE=off $(GO) get -u honnef.co/go/tools/cmd/staticcheck
endif endif
ifdef GOVENDOR ifdef GOVENDOR
@ -212,7 +261,6 @@ precheck::
define PRECHECK_COMMAND_template = define PRECHECK_COMMAND_template =
precheck:: $(1)_precheck precheck:: $(1)_precheck
PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1)))
.PHONY: $(1)_precheck .PHONY: $(1)_precheck
$(1)_precheck: $(1)_precheck:

View file

@ -22,8 +22,54 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"github.com/prometheus/procfs/internal/fs"
) )
// FS represents the pseudo-filesystem proc, which provides an interface to
// kernel data structures.
type FS struct {
sys *fs.FS
}
// NewFS returns a new Bcache using the given sys fs mount point. It will error
// if the mount point can't be read.
func NewFS(mountPoint string) (FS, error) {
if strings.TrimSpace(mountPoint) == "" {
mountPoint = fs.DefaultSysMountPoint
}
fs, err := fs.NewFS(mountPoint)
if err != nil {
return FS{}, err
}
return FS{&fs}, nil
}
// Stats retrieves bcache runtime statistics for each bcache.
func (fs FS) Stats() ([]*Stats, error) {
matches, err := filepath.Glob(fs.sys.Path("fs/bcache/*-*"))
if err != nil {
return nil, err
}
stats := make([]*Stats, 0, len(matches))
for _, uuidPath := range matches {
// "*-*" in glob above indicates the name of the bcache.
name := filepath.Base(uuidPath)
// stats
s, err := GetStats(uuidPath)
if err != nil {
return nil, err
}
s.Name = name
stats = append(stats, s)
}
return stats, nil
}
// ParsePseudoFloat parses the peculiar format produced by bcache's bch_hprint. // ParsePseudoFloat parses the peculiar format produced by bcache's bch_hprint.
func parsePseudoFloat(str string) (float64, error) { func parsePseudoFloat(str string) (float64, error) {
ss := strings.Split(str, ".") ss := strings.Split(str, ".")

View file

@ -43,7 +43,7 @@ func NewBuddyInfo() ([]BuddyInfo, error) {
// NewBuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem. // NewBuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem.
func (fs FS) NewBuddyInfo() ([]BuddyInfo, error) { func (fs FS) NewBuddyInfo() ([]BuddyInfo, error) {
file, err := os.Open(fs.Path("buddyinfo")) file, err := os.Open(fs.proc.Path("buddyinfo"))
if err != nil { if err != nil {
return nil, err return nil, err
} }

File diff suppressed because it is too large Load diff

View file

@ -14,69 +14,24 @@
package procfs package procfs
import ( import (
"fmt" "github.com/prometheus/procfs/internal/fs"
"os"
"path"
"github.com/prometheus/procfs/nfs"
"github.com/prometheus/procfs/xfs"
) )
// FS represents the pseudo-filesystem proc, which provides an interface to // FS represents the pseudo-filesystem sys, which provides an interface to
// kernel data structures. // kernel data structures.
type FS string type FS struct {
proc fs.FS
}
// DefaultMountPoint is the common mount point of the proc filesystem. // DefaultMountPoint is the common mount point of the proc filesystem.
const DefaultMountPoint = "/proc" const DefaultMountPoint = fs.DefaultProcMountPoint
// NewFS returns a new FS mounted under the given mountPoint. It will error // NewFS returns a new proc FS mounted under the given proc mountPoint. It will error
// if the mount point can't be read. // if the mount point dirctory can't be read or is a file.
func NewFS(mountPoint string) (FS, error) { func NewFS(mountPoint string) (FS, error) {
info, err := os.Stat(mountPoint) fs, err := fs.NewFS(mountPoint)
if err != nil { if err != nil {
return "", fmt.Errorf("could not read %s: %s", mountPoint, err) return FS{}, err
} }
if !info.IsDir() { return FS{fs}, nil
return "", fmt.Errorf("mount point %s is not a directory", mountPoint)
}
return FS(mountPoint), nil
}
// Path returns the path of the given subsystem relative to the procfs root.
func (fs FS) Path(p ...string) string {
return path.Join(append([]string{string(fs)}, p...)...)
}
// XFSStats retrieves XFS filesystem runtime statistics.
func (fs FS) XFSStats() (*xfs.Stats, error) {
f, err := os.Open(fs.Path("fs/xfs/stat"))
if err != nil {
return nil, err
}
defer f.Close()
return xfs.ParseStats(f)
}
// NFSClientRPCStats retrieves NFS client RPC statistics.
func (fs FS) NFSClientRPCStats() (*nfs.ClientRPCStats, error) {
f, err := os.Open(fs.Path("net/rpc/nfs"))
if err != nil {
return nil, err
}
defer f.Close()
return nfs.ParseClientRPCStats(f)
}
// NFSdServerRPCStats retrieves NFS daemon RPC statistics.
func (fs FS) NFSdServerRPCStats() (*nfs.ServerRPCStats, error) {
f, err := os.Open(fs.Path("net/rpc/nfsd"))
if err != nil {
return nil, err
}
defer f.Close()
return nfs.ParseServerRPCStats(f)
} }

52
vendor/github.com/prometheus/procfs/internal/fs/fs.go generated vendored Normal file
View file

@ -0,0 +1,52 @@
// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fs
import (
"fmt"
"os"
"path/filepath"
)
const (
// DefaultProcMountPoint is the common mount point of the proc filesystem.
DefaultProcMountPoint = "/proc"
// DefaultSysMountPoint is the common mount point of the sys filesystem.
DefaultSysMountPoint = "/sys"
)
// FS represents a pseudo-filesystem, normally /proc or /sys, which provides an
// interface to kernel data structures.
type FS string
// NewFS returns a new FS mounted under the given mountPoint. It will error
// if the mount point can't be read.
func NewFS(mountPoint string) (FS, error) {
info, err := os.Stat(mountPoint)
if err != nil {
return "", fmt.Errorf("could not read %s: %s", mountPoint, err)
}
if !info.IsDir() {
return "", fmt.Errorf("mount point %s is not a directory", mountPoint)
}
return FS(mountPoint), nil
}
// Path appends the given path elements to the filesystem path, adding separators
// as necessary.
func (fs FS) Path(p ...string) string {
return filepath.Join(append([]string{string(fs)}, p...)...)
}

View file

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// +build !windows // +build linux,!appengine
package util package util

View file

@ -0,0 +1,26 @@
// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux,appengine !linux
package util
import (
"fmt"
)
// SysReadFile is here implemented as a noop for builds that do not support
// the read syscall. For example Windows, or Linux on Google App Engine.
func SysReadFile(file string) (string, error) {
return "", fmt.Errorf("not supported on this platform")
}

View file

@ -74,7 +74,7 @@ func NewIPVSStats() (IPVSStats, error) {
// NewIPVSStats reads the IPVS statistics from the specified `proc` filesystem. // NewIPVSStats reads the IPVS statistics from the specified `proc` filesystem.
func (fs FS) NewIPVSStats() (IPVSStats, error) { func (fs FS) NewIPVSStats() (IPVSStats, error) {
file, err := os.Open(fs.Path("net/ip_vs_stats")) file, err := os.Open(fs.proc.Path("net/ip_vs_stats"))
if err != nil { if err != nil {
return IPVSStats{}, err return IPVSStats{}, err
} }
@ -143,7 +143,7 @@ func NewIPVSBackendStatus() ([]IPVSBackendStatus, error) {
// NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem. // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem.
func (fs FS) NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { func (fs FS) NewIPVSBackendStatus() ([]IPVSBackendStatus, error) {
file, err := os.Open(fs.Path("net/ip_vs")) file, err := os.Open(fs.proc.Path("net/ip_vs"))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -44,7 +44,7 @@ type MDStat struct {
// ParseMDStat parses an mdstat-file and returns a struct with the relevant infos. // ParseMDStat parses an mdstat-file and returns a struct with the relevant infos.
func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { func (fs FS) ParseMDStat() (mdstates []MDStat, err error) {
mdStatusFilePath := fs.Path("mdstat") mdStatusFilePath := fs.proc.Path("mdstat")
content, err := ioutil.ReadFile(mdStatusFilePath) content, err := ioutil.ReadFile(mdStatusFilePath)
if err != nil { if err != nil {
return []MDStat{}, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) return []MDStat{}, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err)

View file

@ -59,7 +59,7 @@ func NewNetDev() (NetDev, error) {
// NewNetDev returns kernel/system statistics read from /proc/net/dev. // NewNetDev returns kernel/system statistics read from /proc/net/dev.
func (fs FS) NewNetDev() (NetDev, error) { func (fs FS) NewNetDev() (NetDev, error) {
return newNetDev(fs.Path("net/dev")) return newNetDev(fs.proc.Path("net/dev"))
} }
// NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev. // NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev.

View file

@ -15,6 +15,13 @@
// Fields are documented in https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/ // Fields are documented in https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/
package nfs package nfs
import (
"os"
"strings"
"github.com/prometheus/procfs/internal/fs"
)
// ReplyCache models the "rc" line. // ReplyCache models the "rc" line.
type ReplyCache struct { type ReplyCache struct {
Hits uint64 Hits uint64
@ -261,3 +268,46 @@ type ServerRPCStats struct {
ServerV4Stats ServerV4Stats ServerV4Stats ServerV4Stats
V4Ops V4Ops V4Ops V4Ops
} }
// FS represents the pseudo-filesystem proc, which provides an interface to
// kernel data structures.
type FS struct {
proc *fs.FS
}
// NewFS returns a new FS mounted under the given mountPoint. It will error
// if the mount point can't be read.
func NewFS(mountPoint string) (FS, error) {
if strings.TrimSpace(mountPoint) == "" {
mountPoint = fs.DefaultProcMountPoint
}
fs, err := fs.NewFS(mountPoint)
if err != nil {
return FS{}, err
}
return FS{&fs}, nil
}
// ClientRPCStats retrieves NFS client RPC statistics
// from proc/net/rpc/nfs.
func (fs FS) ClientRPCStats() (*ClientRPCStats, error) {
f, err := os.Open(fs.proc.Path("net/rpc/nfs"))
if err != nil {
return nil, err
}
defer f.Close()
return ParseClientRPCStats(f)
}
// ServerRPCStats retrieves NFS daemon RPC statistics
// from proc/net/rpc/nfsd.
func (fs FS) ServerRPCStats() (*ServerRPCStats, error) {
f, err := os.Open(fs.proc.Path("net/rpc/nfsd"))
if err != nil {
return nil, err
}
defer f.Close()
return ParseServerRPCStats(f)
}

View file

@ -20,6 +20,8 @@ import (
"os" "os"
"strconv" "strconv"
"strings" "strings"
"github.com/prometheus/procfs/internal/fs"
) )
// Proc provides information about a running process. // Proc provides information about a running process.
@ -27,7 +29,7 @@ type Proc struct {
// The process ID. // The process ID.
PID int PID int
fs FS fs fs.FS
} }
// Procs represents a list of Proc structs. // Procs represents a list of Proc structs.
@ -66,11 +68,11 @@ func AllProcs() (Procs, error) {
// Self returns a process for the current process. // Self returns a process for the current process.
func (fs FS) Self() (Proc, error) { func (fs FS) Self() (Proc, error) {
p, err := os.Readlink(fs.Path("self")) p, err := os.Readlink(fs.proc.Path("self"))
if err != nil { if err != nil {
return Proc{}, err return Proc{}, err
} }
pid, err := strconv.Atoi(strings.Replace(p, string(fs), "", -1)) pid, err := strconv.Atoi(strings.Replace(p, string(fs.proc), "", -1))
if err != nil { if err != nil {
return Proc{}, err return Proc{}, err
} }
@ -79,15 +81,15 @@ func (fs FS) Self() (Proc, error) {
// NewProc returns a process for the given pid. // NewProc returns a process for the given pid.
func (fs FS) NewProc(pid int) (Proc, error) { func (fs FS) NewProc(pid int) (Proc, error) {
if _, err := os.Stat(fs.Path(strconv.Itoa(pid))); err != nil { if _, err := os.Stat(fs.proc.Path(strconv.Itoa(pid))); err != nil {
return Proc{}, err return Proc{}, err
} }
return Proc{PID: pid, fs: fs}, nil return Proc{PID: pid, fs: fs.proc}, nil
} }
// AllProcs returns a list of all currently available processes. // AllProcs returns a list of all currently available processes.
func (fs FS) AllProcs() (Procs, error) { func (fs FS) AllProcs() (Procs, error) {
d, err := os.Open(fs.Path()) d, err := os.Open(fs.proc.Path())
if err != nil { if err != nil {
return Procs{}, err return Procs{}, err
} }
@ -104,7 +106,7 @@ func (fs FS) AllProcs() (Procs, error) {
if err != nil { if err != nil {
continue continue
} }
p = append(p, Proc{PID: int(pid), fs: fs}) p = append(p, Proc{PID: int(pid), fs: fs.proc})
} }
return p, nil return p, nil

View file

@ -64,7 +64,7 @@ func NewPSIStatsForResource(resource string) (PSIStats, error) {
// NewPSIStatsForResource reads pressure stall information from /proc/pressure/<resource> // NewPSIStatsForResource reads pressure stall information from /proc/pressure/<resource>
func (fs FS) NewPSIStatsForResource(resource string) (PSIStats, error) { func (fs FS) NewPSIStatsForResource(resource string) (PSIStats, error) {
file, err := os.Open(fs.Path(fmt.Sprintf("%s/%s", "pressure", resource))) file, err := os.Open(fs.proc.Path(fmt.Sprintf("%s/%s", "pressure", resource)))
if err != nil { if err != nil {
return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %s", resource) return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %s", resource)
} }

View file

@ -18,6 +18,8 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/prometheus/procfs/internal/fs"
) )
// Originally, this USER_HZ value was dynamically retrieved via a sysconf call // Originally, this USER_HZ value was dynamically retrieved via a sysconf call
@ -99,7 +101,7 @@ type ProcStat struct {
// Resident set size in pages. // Resident set size in pages.
RSS int RSS int
fs FS proc fs.FS
} }
// NewStat returns the current status information of the process. // NewStat returns the current status information of the process.
@ -118,7 +120,7 @@ func (p Proc) NewStat() (ProcStat, error) {
var ( var (
ignore int ignore int
s = ProcStat{PID: p.PID, fs: p.fs} s = ProcStat{PID: p.PID, proc: p.fs}
l = bytes.Index(data, []byte("(")) l = bytes.Index(data, []byte("("))
r = bytes.LastIndex(data, []byte(")")) r = bytes.LastIndex(data, []byte(")"))
) )
@ -175,7 +177,8 @@ func (s ProcStat) ResidentMemory() int {
// StartTime returns the unix timestamp of the process in seconds. // StartTime returns the unix timestamp of the process in seconds.
func (s ProcStat) StartTime() (float64, error) { func (s ProcStat) StartTime() (float64, error) {
stat, err := s.fs.NewStat() fs := FS{proc: s.proc}
stat, err := fs.NewStat()
if err != nil { if err != nil {
return 0, err return 0, err
} }

View file

@ -153,7 +153,7 @@ func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) {
func (fs FS) NewStat() (Stat, error) { func (fs FS) NewStat() (Stat, error) {
// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
f, err := os.Open(fs.Path("stat")) f, err := os.Open(fs.proc.Path("stat"))
if err != nil { if err != nil {
return Stat{}, err return Stat{}, err
} }

View file

@ -0,0 +1,188 @@
// Copyright 2018 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !windows
package sysfs
import (
"fmt"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"
"github.com/prometheus/procfs/internal/util"
)
// PowerSupply contains info from files in /sys/class/power_supply for a single power supply.
type PowerSupply struct {
Name string // Power Supply Name
Authentic *int64 `fileName:"authentic"` // /sys/class/power_suppy/<Name>/authentic
Calibrate *int64 `fileName:"calibrate"` // /sys/class/power_suppy/<Name>/calibrate
Capacity *int64 `fileName:"capacity"` // /sys/class/power_suppy/<Name>/capacity
CapacityAlertMax *int64 `fileName:"capacity_alert_max"` // /sys/class/power_suppy/<Name>/capacity_alert_max
CapacityAlertMin *int64 `fileName:"capacity_alert_min"` // /sys/class/power_suppy/<Name>/capacity_alert_min
CapacityLevel string `fileName:"capacity_level"` // /sys/class/power_suppy/<Name>/capacity_level
ChargeAvg *int64 `fileName:"charge_avg"` // /sys/class/power_suppy/<Name>/charge_avg
ChargeControlLimit *int64 `fileName:"charge_control_limit"` // /sys/class/power_suppy/<Name>/charge_control_limit
ChargeControlLimitMax *int64 `fileName:"charge_control_limit_max"` // /sys/class/power_suppy/<Name>/charge_control_limit_max
ChargeCounter *int64 `fileName:"charge_counter"` // /sys/class/power_suppy/<Name>/charge_counter
ChargeEmpty *int64 `fileName:"charge_empty"` // /sys/class/power_suppy/<Name>/charge_empty
ChargeEmptyDesign *int64 `fileName:"charge_empty_design"` // /sys/class/power_suppy/<Name>/charge_empty_design
ChargeFull *int64 `fileName:"charge_full"` // /sys/class/power_suppy/<Name>/charge_full
ChargeFullDesign *int64 `fileName:"charge_full_design"` // /sys/class/power_suppy/<Name>/charge_full_design
ChargeNow *int64 `fileName:"charge_now"` // /sys/class/power_suppy/<Name>/charge_now
ChargeTermCurrent *int64 `fileName:"charge_term_current"` // /sys/class/power_suppy/<Name>/charge_term_current
ChargeType string `fileName:"charge_type"` // /sys/class/power_supply/<Name>/charge_type
ConstantChargeCurrent *int64 `fileName:"constant_charge_current"` // /sys/class/power_suppy/<Name>/constant_charge_current
ConstantChargeCurrentMax *int64 `fileName:"constant_charge_current_max"` // /sys/class/power_suppy/<Name>/constant_charge_current_max
ConstantChargeVoltage *int64 `fileName:"constant_charge_voltage"` // /sys/class/power_suppy/<Name>/constant_charge_voltage
ConstantChargeVoltageMax *int64 `fileName:"constant_charge_voltage_max"` // /sys/class/power_suppy/<Name>/constant_charge_voltage_max
CurrentAvg *int64 `fileName:"current_avg"` // /sys/class/power_suppy/<Name>/current_avg
CurrentBoot *int64 `fileName:"current_boot"` // /sys/class/power_suppy/<Name>/current_boot
CurrentMax *int64 `fileName:"current_max"` // /sys/class/power_suppy/<Name>/current_max
CurrentNow *int64 `fileName:"current_now"` // /sys/class/power_suppy/<Name>/current_now
CycleCount *int64 `fileName:"cycle_count"` // /sys/class/power_suppy/<Name>/cycle_count
EnergyAvg *int64 `fileName:"energy_avg"` // /sys/class/power_supply/<Name>/energy_avg
EnergyEmpty *int64 `fileName:"energy_empty"` // /sys/class/power_suppy/<Name>/energy_empty
EnergyEmptyDesign *int64 `fileName:"energy_empty_design"` // /sys/class/power_suppy/<Name>/energy_empty_design
EnergyFull *int64 `fileName:"energy_full"` // /sys/class/power_suppy/<Name>/energy_full
EnergyFullDesign *int64 `fileName:"energy_full_design"` // /sys/class/power_suppy/<Name>/energy_full_design
EnergyNow *int64 `fileName:"energy_now"` // /sys/class/power_supply/<Name>/energy_now
Health string `fileName:"health"` // /sys/class/power_suppy/<Name>/health
InputCurrentLimit *int64 `fileName:"input_current_limit"` // /sys/class/power_suppy/<Name>/input_current_limit
Manufacturer string `fileName:"manufacturer"` // /sys/class/power_suppy/<Name>/manufacturer
ModelName string `fileName:"model_name"` // /sys/class/power_suppy/<Name>/model_name
Online *int64 `fileName:"online"` // /sys/class/power_suppy/<Name>/online
PowerAvg *int64 `fileName:"power_avg"` // /sys/class/power_suppy/<Name>/power_avg
PowerNow *int64 `fileName:"power_now"` // /sys/class/power_suppy/<Name>/power_now
PrechargeCurrent *int64 `fileName:"precharge_current"` // /sys/class/power_suppy/<Name>/precharge_current
Present *int64 `fileName:"present"` // /sys/class/power_suppy/<Name>/present
Scope string `fileName:"scope"` // /sys/class/power_suppy/<Name>/scope
SerialNumber string `fileName:"serial_number"` // /sys/class/power_suppy/<Name>/serial_number
Status string `fileName:"status"` // /sys/class/power_supply/<Name>/status
Technology string `fileName:"technology"` // /sys/class/power_suppy/<Name>/technology
Temp *int64 `fileName:"temp"` // /sys/class/power_suppy/<Name>/temp
TempAlertMax *int64 `fileName:"temp_alert_max"` // /sys/class/power_suppy/<Name>/temp_alert_max
TempAlertMin *int64 `fileName:"temp_alert_min"` // /sys/class/power_suppy/<Name>/temp_alert_min
TempAmbient *int64 `fileName:"temp_ambient"` // /sys/class/power_suppy/<Name>/temp_ambient
TempAmbientMax *int64 `fileName:"temp_ambient_max"` // /sys/class/power_suppy/<Name>/temp_ambient_max
TempAmbientMin *int64 `fileName:"temp_ambient_min"` // /sys/class/power_suppy/<Name>/temp_ambient_min
TempMax *int64 `fileName:"temp_max"` // /sys/class/power_suppy/<Name>/temp_max
TempMin *int64 `fileName:"temp_min"` // /sys/class/power_suppy/<Name>/temp_min
TimeToEmptyAvg *int64 `fileName:"time_to_empty_avg"` // /sys/class/power_suppy/<Name>/time_to_empty_avg
TimeToEmptyNow *int64 `fileName:"time_to_empty_now"` // /sys/class/power_suppy/<Name>/time_to_empty_now
TimeToFullAvg *int64 `fileName:"time_to_full_avg"` // /sys/class/power_suppy/<Name>/time_to_full_avg
TimeToFullNow *int64 `fileName:"time_to_full_now"` // /sys/class/power_suppy/<Name>/time_to_full_now
Type string `fileName:"type"` // /sys/class/power_supply/<Name>/type
UsbType string `fileName:"usb_type"` // /sys/class/power_supply/<Name>/usb_type
VoltageAvg *int64 `fileName:"voltage_avg"` // /sys/class/power_supply/<Name>/voltage_avg
VoltageBoot *int64 `fileName:"voltage_boot"` // /sys/class/power_suppy/<Name>/voltage_boot
VoltageMax *int64 `fileName:"voltage_max"` // /sys/class/power_suppy/<Name>/voltage_max
VoltageMaxDesign *int64 `fileName:"voltage_max_design"` // /sys/class/power_suppy/<Name>/voltage_max_design
VoltageMin *int64 `fileName:"voltage_min"` // /sys/class/power_suppy/<Name>/voltage_min
VoltageMinDesign *int64 `fileName:"voltage_min_design"` // /sys/class/power_suppy/<Name>/voltage_min_design
VoltageNow *int64 `fileName:"voltage_now"` // /sys/class/power_supply/<Name>/voltage_now
VoltageOCV *int64 `fileName:"voltage_ocv"` // /sys/class/power_suppy/<Name>/voltage_ocv
}
// PowerSupplyClass is a collection of every power supply in /sys/class/power_supply/.
// The map keys are the names of the power supplies.
type PowerSupplyClass map[string]PowerSupply
// NewPowerSupplyClass returns info for all power supplies read from /sys/class/power_supply/.
func NewPowerSupplyClass() (PowerSupplyClass, error) {
fs, err := NewFS(DefaultMountPoint)
if err != nil {
return nil, err
}
return fs.NewPowerSupplyClass()
}
// NewPowerSupplyClass returns info for all power supplies read from /sys/class/power_supply/.
func (fs FS) NewPowerSupplyClass() (PowerSupplyClass, error) {
path := fs.sys.Path("class/power_supply")
powerSupplyDirs, err := ioutil.ReadDir(path)
if err != nil {
return PowerSupplyClass{}, fmt.Errorf("cannot access %s dir %s", path, err)
}
powerSupplyClass := PowerSupplyClass{}
for _, powerSupplyDir := range powerSupplyDirs {
powerSupply, err := powerSupplyClass.parsePowerSupply(path + "/" + powerSupplyDir.Name())
if err != nil {
return nil, err
}
powerSupply.Name = powerSupplyDir.Name()
powerSupplyClass[powerSupplyDir.Name()] = *powerSupply
}
return powerSupplyClass, nil
}
func (psc PowerSupplyClass) parsePowerSupply(powerSupplyPath string) (*PowerSupply, error) {
powerSupply := PowerSupply{}
powerSupplyElem := reflect.ValueOf(&powerSupply).Elem()
powerSupplyType := reflect.TypeOf(powerSupply)
//start from 1 - skip the Name field
for i := 1; i < powerSupplyElem.NumField(); i++ {
fieldType := powerSupplyType.Field(i)
fieldValue := powerSupplyElem.Field(i)
if fieldType.Tag.Get("fileName") == "" {
panic(fmt.Errorf("field %s does not have a filename tag", fieldType.Name))
}
value, err := util.SysReadFile(powerSupplyPath + "/" + fieldType.Tag.Get("fileName"))
if err != nil {
if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
continue
}
return nil, fmt.Errorf("could not access file %s: %s", fieldType.Tag.Get("fileName"), err)
}
switch fieldValue.Kind() {
case reflect.String:
fieldValue.SetString(value)
case reflect.Ptr:
var int64ptr *int64
switch fieldValue.Type() {
case reflect.TypeOf(int64ptr):
var intValue int64
if strings.HasPrefix(value, "0x") {
intValue, err = strconv.ParseInt(value[2:], 16, 64)
if err != nil {
return nil, fmt.Errorf("expected hex value for %s, got: %s", fieldType.Name, value)
}
} else {
intValue, err = strconv.ParseInt(value, 10, 64)
if err != nil {
return nil, fmt.Errorf("expected Uint64 value for %s, got: %s", fieldType.Name, value)
}
}
fieldValue.Set(reflect.ValueOf(&intValue))
default:
return nil, fmt.Errorf("unhandled pointer type %q", fieldValue.Type())
}
default:
return nil, fmt.Errorf("unhandled type %q", fieldValue.Kind())
}
}
return &powerSupply, nil
}

View file

@ -37,7 +37,7 @@ type ClassThermalZoneStats struct {
// NewClassThermalZoneStats returns Thermal Zone metrics for all zones. // NewClassThermalZoneStats returns Thermal Zone metrics for all zones.
func (fs FS) NewClassThermalZoneStats() ([]ClassThermalZoneStats, error) { func (fs FS) NewClassThermalZoneStats() ([]ClassThermalZoneStats, error) {
zones, err := filepath.Glob(fs.Path("class/thermal/thermal_zone[0-9]*")) zones, err := filepath.Glob(fs.sys.Path("class/thermal/thermal_zone[0-9]*"))
if err != nil { if err != nil {
return []ClassThermalZoneStats{}, err return []ClassThermalZoneStats{}, err
} }

File diff suppressed because it is too large Load diff

View file

@ -14,95 +14,24 @@
package sysfs package sysfs
import ( import (
"fmt" "github.com/prometheus/procfs/internal/fs"
"os"
"path/filepath"
"github.com/prometheus/procfs/bcache"
"github.com/prometheus/procfs/xfs"
) )
// FS represents the pseudo-filesystem sys, which provides an interface to // FS represents the pseudo-filesystem sys, which provides an interface to
// kernel data structures. // kernel data structures.
type FS string type FS struct {
sys fs.FS
}
// DefaultMountPoint is the common mount point of the sys filesystem. // DefaultMountPoint is the common mount point of the sys filesystem.
const DefaultMountPoint = "/sys" const DefaultMountPoint = fs.DefaultSysMountPoint
// NewFS returns a new FS mounted under the given mountPoint. It will error // NewFS returns a new FS mounted under the given mountPoint. It will error
// if the mount point can't be read. // if the mount point can't be read.
func NewFS(mountPoint string) (FS, error) { func NewFS(mountPoint string) (FS, error) {
info, err := os.Stat(mountPoint) fs, err := fs.NewFS(mountPoint)
if err != nil { if err != nil {
return "", fmt.Errorf("could not read %s: %s", mountPoint, err) return FS{}, err
} }
if !info.IsDir() { return FS{fs}, nil
return "", fmt.Errorf("mount point %s is not a directory", mountPoint)
}
return FS(mountPoint), nil
}
// Path returns the path of the given subsystem relative to the sys root.
func (fs FS) Path(p ...string) string {
return filepath.Join(append([]string{string(fs)}, p...)...)
}
// XFSStats retrieves XFS filesystem runtime statistics for each mounted XFS
// filesystem. Only available on kernel 4.4+. On older kernels, an empty
// slice of *xfs.Stats will be returned.
func (fs FS) XFSStats() ([]*xfs.Stats, error) {
matches, err := filepath.Glob(fs.Path("fs/xfs/*/stats/stats"))
if err != nil {
return nil, err
}
stats := make([]*xfs.Stats, 0, len(matches))
for _, m := range matches {
f, err := os.Open(m)
if err != nil {
return nil, err
}
// "*" used in glob above indicates the name of the filesystem.
name := filepath.Base(filepath.Dir(filepath.Dir(m)))
// File must be closed after parsing, regardless of success or
// failure. Defer is not used because of the loop.
s, err := xfs.ParseStats(f)
_ = f.Close()
if err != nil {
return nil, err
}
s.Name = name
stats = append(stats, s)
}
return stats, nil
}
// BcacheStats retrieves bcache runtime statistics for each bcache.
func (fs FS) BcacheStats() ([]*bcache.Stats, error) {
matches, err := filepath.Glob(fs.Path("fs/bcache/*-*"))
if err != nil {
return nil, err
}
stats := make([]*bcache.Stats, 0, len(matches))
for _, uuidPath := range matches {
// "*-*" in glob above indicates the name of the bcache.
name := filepath.Base(uuidPath)
// stats
s, err := bcache.GetStats(uuidPath)
if err != nil {
return nil, err
}
s.Name = name
stats = append(stats, s)
}
return stats, nil
} }

View file

@ -19,6 +19,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
@ -26,6 +27,8 @@ import (
"github.com/prometheus/procfs/internal/util" "github.com/prometheus/procfs/internal/util"
) )
const netclassPath = "class/net"
// NetClassIface contains info from files in /sys/class/net/<iface> // NetClassIface contains info from files in /sys/class/net/<iface>
// for single interface (iface). // for single interface (iface).
type NetClassIface struct { type NetClassIface struct {
@ -72,26 +75,42 @@ func NewNetClass() (NetClass, error) {
return fs.NewNetClass() return fs.NewNetClass()
} }
// NewNetClass returns info for all net interfaces (iface) read from /sys/class/net/<iface>. // NetClassDevices scans /sys/class/net for devices and returns them as a list of names.
func (fs FS) NewNetClass() (NetClass, error) { func (fs FS) NetClassDevices() ([]string, error) {
path := fs.Path("class/net") var res []string
path := fs.sys.Path(netclassPath)
devices, err := ioutil.ReadDir(path) devices, err := ioutil.ReadDir(path)
if err != nil { if err != nil {
return NetClass{}, fmt.Errorf("cannot access %s dir %s", path, err) return res, fmt.Errorf("cannot access %s dir %s", path, err)
} }
netClass := NetClass{}
for _, deviceDir := range devices { for _, deviceDir := range devices {
if deviceDir.Mode().IsRegular() { if deviceDir.Mode().IsRegular() {
continue continue
} }
interfaceClass, err := netClass.parseNetClassIface(path + "/" + deviceDir.Name()) res = append(res, deviceDir.Name())
}
return res, nil
}
// NewNetClass returns info for all net interfaces (iface) read from /sys/class/net/<iface>.
func (fs FS) NewNetClass() (NetClass, error) {
devices, err := fs.NetClassDevices()
if err != nil {
return nil, err
}
path := fs.sys.Path(netclassPath)
netClass := NetClass{}
for _, deviceDir := range devices {
interfaceClass, err := netClass.parseNetClassIface(filepath.Join(path, deviceDir))
if err != nil { if err != nil {
return nil, err return nil, err
} }
interfaceClass.Name = deviceDir.Name() interfaceClass.Name = deviceDir
netClass[deviceDir.Name()] = *interfaceClass netClass[deviceDir] = *interfaceClass
} }
return netClass, nil return netClass, nil
} }

View file

@ -60,7 +60,7 @@ func NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) { func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
var g errgroup.Group var g errgroup.Group
cpus, err := filepath.Glob(fs.Path("devices/system/cpu/cpu[0-9]*")) cpus, err := filepath.Glob(fs.sys.Path("devices/system/cpu/cpu[0-9]*"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -70,10 +70,10 @@ func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
cpuName := strings.TrimPrefix(filepath.Base(cpu), "cpu") cpuName := strings.TrimPrefix(filepath.Base(cpu), "cpu")
cpuCpufreqPath := filepath.Join(cpu, "cpufreq") cpuCpufreqPath := filepath.Join(cpu, "cpufreq")
if _, err := os.Stat(cpuCpufreqPath); os.IsNotExist(err) { _, err = os.Stat(cpuCpufreqPath)
if os.IsNotExist(err) {
continue continue
} } else if err != nil {
if err != nil {
return nil, err return nil, err
} }

View file

@ -97,7 +97,7 @@ func NewXfrmStat() (XfrmStat, error) {
// NewXfrmStat reads the xfrm_stat statistics from the 'proc' filesystem. // NewXfrmStat reads the xfrm_stat statistics from the 'proc' filesystem.
func (fs FS) NewXfrmStat() (XfrmStat, error) { func (fs FS) NewXfrmStat() (XfrmStat, error) {
file, err := os.Open(fs.Path("net/xfrm_stat")) file, err := os.Open(fs.proc.Path("net/xfrm_stat"))
if err != nil { if err != nil {
return XfrmStat{}, err return XfrmStat{}, err
} }

View file

@ -14,6 +14,14 @@
// Package xfs provides access to statistics exposed by the XFS filesystem. // Package xfs provides access to statistics exposed by the XFS filesystem.
package xfs package xfs
import (
"os"
"path/filepath"
"strings"
"github.com/prometheus/procfs/internal/fs"
)
// Stats contains XFS filesystem runtime statistics, parsed from // Stats contains XFS filesystem runtime statistics, parsed from
// /proc/fs/xfs/stat. // /proc/fs/xfs/stat.
// //
@ -161,3 +169,76 @@ type ExtendedPrecisionStats struct {
WriteBytes uint64 WriteBytes uint64
ReadBytes uint64 ReadBytes uint64
} }
// FS represents the pseudo-filesystems proc and sys, which provides an interface to
// kernel data structures.
type FS struct {
proc *fs.FS
sys *fs.FS
}
// NewFS returns a new XFS handle using the given proc and sys mountPoints. It will error
// if either of the mounts point can't be read.
func NewFS(procMountPoint string, sysMountPoint string) (FS, error) {
if strings.TrimSpace(procMountPoint) == "" {
procMountPoint = fs.DefaultProcMountPoint
}
procfs, err := fs.NewFS(procMountPoint)
if err != nil {
return FS{}, err
}
if strings.TrimSpace(sysMountPoint) == "" {
sysMountPoint = fs.DefaultSysMountPoint
}
sysfs, err := fs.NewFS(sysMountPoint)
if err != nil {
return FS{}, err
}
return FS{&procfs, &sysfs}, nil
}
// ProcStat retrieves XFS filesystem runtime statistics
// from proc/fs/xfs/stat given the profs mount point.
func (fs FS) ProcStat() (*Stats, error) {
f, err := os.Open(fs.proc.Path("fs/xfs/stat"))
if err != nil {
return nil, err
}
defer f.Close()
return ParseStats(f)
}
// SysStats retrieves XFS filesystem runtime statistics for each mounted XFS
// filesystem. Only available on kernel 4.4+. On older kernels, an empty
// slice of *xfs.Stats will be returned.
func (fs FS) SysStats() ([]*Stats, error) {
matches, err := filepath.Glob(fs.sys.Path("fs/xfs/*/stats/stats"))
if err != nil {
return nil, err
}
stats := make([]*Stats, 0, len(matches))
for _, m := range matches {
f, err := os.Open(m)
if err != nil {
return nil, err
}
// "*" used in glob above indicates the name of the filesystem.
name := filepath.Base(filepath.Dir(filepath.Dir(m)))
// File must be closed after parsing, regardless of success or
// failure. Defer is not used because of the loop.
s, err := ParseStats(f)
_ = f.Close()
if err != nil {
return nil, err
}
s.Name = name
stats = append(stats, s)
}
return stats, nil
}

5
vendor/modules.txt vendored
View file

@ -43,12 +43,13 @@ github.com/prometheus/common/version
github.com/prometheus/common/expfmt github.com/prometheus/common/expfmt
github.com/prometheus/common/model github.com/prometheus/common/model
github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
# github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd # github.com/prometheus/procfs v0.0.0-20190503130316-740c07785007
github.com/prometheus/procfs github.com/prometheus/procfs
github.com/prometheus/procfs/bcache github.com/prometheus/procfs/bcache
github.com/prometheus/procfs/nfs github.com/prometheus/procfs/nfs
github.com/prometheus/procfs/sysfs github.com/prometheus/procfs/sysfs
github.com/prometheus/procfs/xfs github.com/prometheus/procfs/xfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util github.com/prometheus/procfs/internal/util
# github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745 # github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745
github.com/siebenmann/go-kstat github.com/siebenmann/go-kstat
@ -61,7 +62,7 @@ golang.org/x/net/ipv4
golang.org/x/net/bpf golang.org/x/net/bpf
golang.org/x/net/internal/iana golang.org/x/net/internal/iana
golang.org/x/net/internal/socket golang.org/x/net/internal/socket
# golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 # golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sync/errgroup golang.org/x/sync/errgroup
# golang.org/x/sys v0.0.0-20190402142545-baf5eb976a8c # golang.org/x/sys v0.0.0-20190402142545-baf5eb976a8c
golang.org/x/sys/unix golang.org/x/sys/unix