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
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs/bcache"
"github.com/prometheus/procfs/sysfs"
)
func init() {
@ -30,13 +29,13 @@ func init() {
// A bcacheCollector is a Collector which gathers metrics from Linux bcache.
type bcacheCollector struct {
fs sysfs.FS
fs bcache.FS
}
// NewBcacheCollector returns a newly allocated bcacheCollector.
// It exposes a number of Linux bcache statistics.
func NewBcacheCollector() (Collector, error) {
fs, err := sysfs.NewFS(*sysPath)
fs, err := bcache.NewFS(*sysPath)
if err != nil {
return nil, fmt.Errorf("failed to open sysfs: %v", err)
}
@ -49,7 +48,7 @@ func NewBcacheCollector() (Collector, error) {
// Update reads and exposes bcache stats.
// It implements the Collector interface.
func (c *bcacheCollector) Update(ch chan<- prometheus.Metric) error {
stats, err := c.fs.BcacheStats()
stats, err := c.fs.Stats()
if err != nil {
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/common/log"
"github.com/prometheus/procfs"
"github.com/prometheus/procfs/nfs"
)
@ -29,7 +28,7 @@ const (
)
type nfsCollector struct {
fs procfs.FS
fs nfs.FS
nfsNetReadsDesc *prometheus.Desc
nfsNetConnectionsDesc *prometheus.Desc
nfsRPCOperationsDesc *prometheus.Desc
@ -44,7 +43,7 @@ func init() {
// NewNfsCollector returns a new Collector exposing NFS statistics.
func NewNfsCollector() (Collector, error) {
fs, err := procfs.NewFS(*procPath)
fs, err := nfs.NewFS(*procPath)
if err != nil {
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 {
stats, err := c.fs.NFSClientRPCStats()
stats, err := c.fs.ClientRPCStats()
if err != nil {
if os.IsNotExist(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/common/log"
"github.com/prometheus/procfs"
"github.com/prometheus/procfs/nfs"
)
// A nfsdCollector is a Collector which gathers metrics from /proc/net/rpc/nfsd.
// See: https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/
type nfsdCollector struct {
fs procfs.FS
fs nfs.FS
requestsDesc *prometheus.Desc
}
@ -40,7 +39,7 @@ const (
// NewNFSdCollector returns a new Collector exposing /proc/net/rpc/nfsd statistics.
func NewNFSdCollector() (Collector, error) {
fs, err := procfs.NewFS(*procPath)
fs, err := nfs.NewFS(*procPath)
if err != nil {
return nil, fmt.Errorf("failed to open procfs: %v", err)
}
@ -57,7 +56,7 @@ func NewNFSdCollector() (Collector, error) {
// Update implements Collector.
func (c *nfsdCollector) Update(ch chan<- prometheus.Metric) error {
stats, err := c.fs.NFSdServerRPCStats()
stats, err := c.fs.ServerRPCStats()
if err != nil {
if os.IsNotExist(err) {
log.Debugf("Not collecting NFSd metrics: %s", err)

View file

@ -17,13 +17,12 @@ import (
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs/sysfs"
"github.com/prometheus/procfs/xfs"
)
// An xfsCollector is a Collector which gathers metrics from XFS filesystems.
type xfsCollector struct {
fs sysfs.FS
fs xfs.FS
}
func init() {
@ -32,7 +31,7 @@ func init() {
// NewXFSCollector returns a new Collector exposing XFS statistics.
func NewXFSCollector() (Collector, error) {
fs, err := sysfs.NewFS(*sysPath)
fs, err := xfs.NewFS(*procPath, *sysPath)
if err != nil {
return nil, fmt.Errorf("failed to open sysfs: %v", err)
}
@ -44,7 +43,7 @@ func NewXFSCollector() (Collector, error) {
// Update implements Collector.
func (c *xfsCollector) Update(ch chan<- prometheus.Metric) error {
stats, err := c.fs.XFSStats()
stats, err := c.fs.SysStats()
if err != nil {
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_model v0.0.0-20190129233127-fd36f4220a90
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/sirupsen/logrus v1.4.1 // indirect
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
github.com/stretchr/testify v1.3.0 // 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
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/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-20190209105433-f8d8b3f739bd h1:pi7bGw6n4tfgHQtWDxJBBLYVdFr1GlfQEsDOyCDDFMM=
github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.0-20190503130316-740c07785007 h1:gT4PpkbWSQM4J8fup/aXeQhY5jLDyHuPq8y2dHspqFw=
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/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8=
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-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-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
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-20181116152217-5ac8a444bdc5/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
touch $@
update_fixtures: fixtures.ttar sysfs/fixtures.ttar
%fixtures.ttar: %/fixtures
rm -v $(dir $*)fixtures/.unpacked
./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/
update_fixtures:
rm -vf fixtures/.unpacked
./ttar -c -f fixtures.ttar fixtures/
.PHONY: build
build:
.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
FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH)))
GOOPTS ?=
GOHOSTOS ?= $(shell $(GO) env GOHOSTOS)
GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH)
GO_VERSION ?= $(shell $(GO) version)
GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))
PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.')
unexport GOVENDOR
GOVENDOR :=
GO111MODULE :=
ifeq (, $(PRE_GO_111))
ifneq (,$(wildcard go.mod))
# 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).
GOVENDOR := $(FIRST_GOPATH)/bin/govendor
endif
unexport GO111MODULE
endif
PROMU := $(FIRST_GOPATH)/bin/promu
STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck
pkgs = ./...
GO_VERSION ?= $(shell $(GO) version)
GO_BUILD_PLATFORM ?= $(subst /,-,$(lastword $(GO_VERSION)))
ifeq (arm, $(GOHOSTARCH))
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
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)
BIN_DIR ?= $(shell pwd)
DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
DOCKER_REPO ?= prom
.PHONY: all
all: precheck style staticcheck unused build test
DOCKER_ARCHS ?= amd64
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
# allows a new "build" target to be defined in a Makefile which includes this
# one and override "common-build" without override warnings.
%: common-% ;
.PHONY: common-all
common-all: precheck style check_license lint unused build test
.PHONY: common-style
common-style:
@echo ">> checking code style"
@ -102,6 +129,15 @@ common-check_license:
exit 1; \
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
common-test-short:
@echo ">> running short tests"
@ -110,26 +146,35 @@ common-test-short:
.PHONY: common-test
common-test:
@echo ">> running all tests"
GO111MODULE=$(GO111MODULE) $(GO) test -race $(GOOPTS) $(pkgs)
GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs)
.PHONY: common-format
common-format:
@echo ">> formatting code"
GO111MODULE=$(GO111MODULE) $(GO) fmt $(GOOPTS) $(pkgs)
GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs)
.PHONY: common-vet
common-vet:
@echo ">> vetting code"
GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs)
.PHONY: common-staticcheck
common-staticcheck: $(STATICCHECK)
@echo ">> running staticcheck"
.PHONY: common-lint
common-lint: $(GOLANGCI_LINT)
ifdef GOLANGCI_LINT
@echo ">> running golangci-lint"
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
$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs)
$(GOLANGCI_LINT) run $(pkgs)
endif
endif
# For backward-compatibility.
.PHONY: common-staticcheck
common-staticcheck: lint
.PHONY: common-unused
common-unused: $(GOVENDOR)
@ -140,8 +185,9 @@ else
ifdef GO111MODULE
@echo ">> running check for unused/missing packages in go.mod"
GO111MODULE=$(GO111MODULE) $(GO) mod tidy
ifeq (,$(wildcard vendor))
@git diff --exit-code -- go.sum go.mod
ifneq (,$(wildcard vendor))
else
@echo ">> running check for unused packages in vendor/"
GO111MODULE=$(GO111MODULE) $(GO) mod vendor
@git diff --exit-code -- go.sum go.mod vendor/
@ -159,45 +205,48 @@ common-tarball: promu
@echo ">> building release tarball"
$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR)
.PHONY: common-docker
common-docker:
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" .
.PHONY: common-docker $(BUILD_DOCKER_ARCHS)
common-docker: $(BUILD_DOCKER_ARCHS)
$(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
common-docker-publish:
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)"
.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
.PHONY: common-docker-tag-latest
common-docker-tag-latest:
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):latest"
.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
$(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
promu: $(PROMU)
$(PROMU):
curl -s -L $(PROMU_URL) | tar -xvz -C /tmp
mkdir -v -p $(FIRST_GOPATH)/bin
cp -v /tmp/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(PROMU)
$(eval PROMU_TMP := $(shell mktemp -d))
curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP)
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
proto:
@echo ">> generating code from proto files"
@./scripts/genproto.sh
.PHONY: $(STATICCHECK)
$(STATICCHECK):
ifdef GO111MODULE
# Get staticcheck from a temporary directory to avoid modifying the local go.{mod,sum}.
# See https://github.com/golang/go/issues/27643.
# For now, we are using the next branch of staticcheck because master isn't compatible yet with Go modules.
tmpModule=$$(mktemp -d 2>&1) && \
mkdir -p $${tmpModule}/staticcheck && \
cd "$${tmpModule}"/staticcheck && \
GO111MODULE=on $(GO) mod init example.com/staticcheck && \
GO111MODULE=on GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck@next && \
rm -rf $${tmpModule};
else
GOOS= GOARCH= GO111MODULE=off $(GO) get -u honnef.co/go/tools/cmd/staticcheck
ifdef GOLANGCI_LINT
$(GOLANGCI_LINT):
mkdir -p $(FIRST_GOPATH)/bin
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
endif
ifdef GOVENDOR
@ -212,7 +261,6 @@ precheck::
define PRECHECK_COMMAND_template =
precheck:: $(1)_precheck
PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1)))
.PHONY: $(1)_precheck
$(1)_precheck:

View file

@ -22,8 +22,54 @@ import (
"path/filepath"
"strconv"
"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.
func parsePseudoFloat(str string) (float64, error) {
ss := strings.Split(str, ".")

View file

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

File diff suppressed because it is too large Load diff

View file

@ -14,69 +14,24 @@
package procfs
import (
"fmt"
"os"
"path"
"github.com/prometheus/procfs/nfs"
"github.com/prometheus/procfs/xfs"
"github.com/prometheus/procfs/internal/fs"
)
// 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.
type FS string
type FS struct {
proc fs.FS
}
// 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
// if the mount point can't be read.
// NewFS returns a new proc FS mounted under the given proc mountPoint. It will error
// if the mount point dirctory can't be read or is a file.
func NewFS(mountPoint string) (FS, error) {
info, err := os.Stat(mountPoint)
fs, err := fs.NewFS(mountPoint)
if err != nil {
return "", fmt.Errorf("could not read %s: %s", mountPoint, err)
return FS{}, err
}
if !info.IsDir() {
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)
return FS{fs}, nil
}

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
// limitations under the License.
// +build !windows
// +build linux,!appengine
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.
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 {
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.
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 {
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.
func (fs FS) ParseMDStat() (mdstates []MDStat, err error) {
mdStatusFilePath := fs.Path("mdstat")
mdStatusFilePath := fs.proc.Path("mdstat")
content, err := ioutil.ReadFile(mdStatusFilePath)
if err != nil {
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.
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.

View file

@ -15,6 +15,13 @@
// Fields are documented in https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/
package nfs
import (
"os"
"strings"
"github.com/prometheus/procfs/internal/fs"
)
// ReplyCache models the "rc" line.
type ReplyCache struct {
Hits uint64
@ -261,3 +268,46 @@ type ServerRPCStats struct {
ServerV4Stats ServerV4Stats
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"
"strconv"
"strings"
"github.com/prometheus/procfs/internal/fs"
)
// Proc provides information about a running process.
@ -27,7 +29,7 @@ type Proc struct {
// The process ID.
PID int
fs FS
fs fs.FS
}
// Procs represents a list of Proc structs.
@ -66,11 +68,11 @@ func AllProcs() (Procs, error) {
// Self returns a process for the current process.
func (fs FS) Self() (Proc, error) {
p, err := os.Readlink(fs.Path("self"))
p, err := os.Readlink(fs.proc.Path("self"))
if err != nil {
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 {
return Proc{}, err
}
@ -79,15 +81,15 @@ func (fs FS) Self() (Proc, error) {
// NewProc returns a process for the given pid.
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{PID: pid, fs: fs}, nil
return Proc{PID: pid, fs: fs.proc}, nil
}
// AllProcs returns a list of all currently available processes.
func (fs FS) AllProcs() (Procs, error) {
d, err := os.Open(fs.Path())
d, err := os.Open(fs.proc.Path())
if err != nil {
return Procs{}, err
}
@ -104,7 +106,7 @@ func (fs FS) AllProcs() (Procs, error) {
if err != nil {
continue
}
p = append(p, Proc{PID: int(pid), fs: fs})
p = append(p, Proc{PID: int(pid), fs: fs.proc})
}
return p, nil

View file

@ -64,7 +64,7 @@ func NewPSIStatsForResource(resource string) (PSIStats, error) {
// NewPSIStatsForResource reads pressure stall information from /proc/pressure/<resource>
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 {
return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %s", resource)
}

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -14,95 +14,24 @@
package sysfs
import (
"fmt"
"os"
"path/filepath"
"github.com/prometheus/procfs/bcache"
"github.com/prometheus/procfs/xfs"
"github.com/prometheus/procfs/internal/fs"
)
// FS represents the pseudo-filesystem sys, which provides an interface to
// kernel data structures.
type FS string
type FS struct {
sys fs.FS
}
// 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
// if the mount point can't be read.
func NewFS(mountPoint string) (FS, error) {
info, err := os.Stat(mountPoint)
fs, err := fs.NewFS(mountPoint)
if err != nil {
return "", fmt.Errorf("could not read %s: %s", mountPoint, err)
return FS{}, err
}
if !info.IsDir() {
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
return FS{fs}, nil
}

View file

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

View file

@ -60,7 +60,7 @@ func NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
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 {
return nil, err
}
@ -70,10 +70,10 @@ func (fs FS) NewSystemCpufreq() ([]SystemCPUCpufreqStats, error) {
cpuName := strings.TrimPrefix(filepath.Base(cpu), "cpu")
cpuCpufreqPath := filepath.Join(cpu, "cpufreq")
if _, err := os.Stat(cpuCpufreqPath); os.IsNotExist(err) {
_, err = os.Stat(cpuCpufreqPath)
if os.IsNotExist(err) {
continue
}
if err != nil {
} else if err != nil {
return nil, err
}

View file

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

View file

@ -14,6 +14,14 @@
// Package xfs provides access to statistics exposed by the XFS filesystem.
package xfs
import (
"os"
"path/filepath"
"strings"
"github.com/prometheus/procfs/internal/fs"
)
// Stats contains XFS filesystem runtime statistics, parsed from
// /proc/fs/xfs/stat.
//
@ -161,3 +169,76 @@ type ExtendedPrecisionStats struct {
WriteBytes 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/model
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/bcache
github.com/prometheus/procfs/nfs
github.com/prometheus/procfs/sysfs
github.com/prometheus/procfs/xfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
# github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745
github.com/siebenmann/go-kstat
@ -61,7 +62,7 @@ golang.org/x/net/ipv4
golang.org/x/net/bpf
golang.org/x/net/internal/iana
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/sys v0.0.0-20190402142545-baf5eb976a8c
golang.org/x/sys/unix