Add Btrfs collector (#1512)
* Add procfs/btrfs to vendor folder * Add Btrfs collector Resolves #1100 Signed-off-by: Silke Hofstra <silke@slxh.eu>
This commit is contained in:
parent
ca1ac435ea
commit
8faa843fc4
9 changed files with 1272 additions and 0 deletions
67
vendor/github.com/prometheus/procfs/btrfs/btrfs.go
generated
vendored
Normal file
67
vendor/github.com/prometheus/procfs/btrfs/btrfs.go
generated
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// 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 btrfs provides access to statistics exposed by Btrfs filesystems.
|
||||
package btrfs
|
||||
|
||||
// Stats contains statistics for a single Btrfs filesystem.
|
||||
// See Linux fs/btrfs/sysfs.c for more information.
|
||||
type Stats struct {
|
||||
UUID, Label string
|
||||
Allocation Allocation
|
||||
Devices map[string]*Device
|
||||
Features []string
|
||||
CloneAlignment uint64
|
||||
NodeSize uint64
|
||||
QuotaOverride uint64
|
||||
SectorSize uint64
|
||||
}
|
||||
|
||||
// Allocation contains allocation statistics for data, metadata and system data.
|
||||
type Allocation struct {
|
||||
GlobalRsvReserved, GlobalRsvSize uint64
|
||||
Data, Metadata, System *AllocationStats
|
||||
}
|
||||
|
||||
// AllocationStats contains allocation statistics for a data type.
|
||||
type AllocationStats struct {
|
||||
// Usage statistics
|
||||
DiskUsedBytes uint64
|
||||
DiskTotalBytes uint64
|
||||
MayUseBytes uint64
|
||||
PinnedBytes uint64
|
||||
TotalPinnedBytes uint64
|
||||
ReadOnlyBytes uint64
|
||||
ReservedBytes uint64
|
||||
UsedBytes uint64
|
||||
TotalBytes uint64
|
||||
|
||||
// Flags marking filesystem state
|
||||
// See Linux fs/btrfs/ctree.h for more information.
|
||||
Flags uint64
|
||||
|
||||
// Additional disk usage statistics depending on the disk layout.
|
||||
// At least one of these will exist and not be nil.
|
||||
Layouts map[string]*LayoutUsage
|
||||
}
|
||||
|
||||
// LayoutUsage contains additional usage statistics for a disk layout.
|
||||
type LayoutUsage struct {
|
||||
UsedBytes, TotalBytes uint64
|
||||
Ratio float64
|
||||
}
|
||||
|
||||
// Device contains information about a device that is part of a Btrfs filesystem.
|
||||
type Device struct {
|
||||
Size uint64
|
||||
}
|
||||
251
vendor/github.com/prometheus/procfs/btrfs/get.go
generated
vendored
Normal file
251
vendor/github.com/prometheus/procfs/btrfs/get.go
generated
vendored
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
// 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 btrfs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/procfs/internal/fs"
|
||||
"github.com/prometheus/procfs/internal/util"
|
||||
)
|
||||
|
||||
// SectorSize contains the Linux sector size.
|
||||
// > Linux always considers sectors to be 512 bytes long independently
|
||||
// > of the devices real block size.
|
||||
const SectorSize = 512
|
||||
|
||||
// FS represents the pseudo-filesystem sys, which provides an interface to
|
||||
// kernel data structures.
|
||||
type FS struct {
|
||||
sys *fs.FS
|
||||
}
|
||||
|
||||
// NewDefaultFS returns a new Bcache using the default sys fs mount point. It will error
|
||||
// if the mount point can't be read.
|
||||
func NewDefaultFS() (FS, error) {
|
||||
return NewFS(fs.DefaultSysMountPoint)
|
||||
}
|
||||
|
||||
// NewFS returns a new Btrfs filesystem 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
|
||||
}
|
||||
sys, err := fs.NewFS(mountPoint)
|
||||
if err != nil {
|
||||
return FS{}, err
|
||||
}
|
||||
return FS{&sys}, nil
|
||||
}
|
||||
|
||||
// Stats retrieves Btrfs filesystem runtime statistics for each mounted Btrfs filesystem.
|
||||
func (fs FS) Stats() ([]*Stats, error) {
|
||||
matches, err := filepath.Glob(fs.sys.Path("fs/btrfs/*-*"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats := make([]*Stats, 0, len(matches))
|
||||
for _, uuidPath := range matches {
|
||||
s, err := GetStats(uuidPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the UUID from the path when it could not be retrieved from the filesystem.
|
||||
if s.UUID == "" {
|
||||
s.UUID = filepath.Base(uuidPath)
|
||||
}
|
||||
|
||||
stats = append(stats, s)
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// GetStats collects all Btrfs statistics from sysfs
|
||||
func GetStats(uuidPath string) (*Stats, error) {
|
||||
r := &reader{path: uuidPath}
|
||||
s := r.readFilesystemStats()
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type reader struct {
|
||||
path string
|
||||
err error
|
||||
devCount int
|
||||
}
|
||||
|
||||
// readFile reads a file relative to the path of the reader.
|
||||
// Non-existing files are ignored.
|
||||
func (r *reader) readFile(n string) string {
|
||||
b, err := util.SysReadFile(path.Join(r.path, n))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
r.err = err
|
||||
}
|
||||
return strings.TrimSpace(string(b))
|
||||
}
|
||||
|
||||
// readValues reads a number of numerical values into an uint64 slice.
|
||||
func (r *reader) readValue(n string) (v uint64) {
|
||||
// Read value from file
|
||||
s := r.readFile(n)
|
||||
if r.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Convert number
|
||||
v, _ = strconv.ParseUint(s, 10, 64)
|
||||
return
|
||||
}
|
||||
|
||||
// listFiles returns a list of files for a directory of the reader.
|
||||
func (r *reader) listFiles(p string) []string {
|
||||
files, err := ioutil.ReadDir(path.Join(r.path, p))
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return nil
|
||||
}
|
||||
|
||||
names := make([]string, len(files))
|
||||
for i, f := range files {
|
||||
names[i] = f.Name()
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// readAllocationStats reads Btrfs allocation data for the current path.
|
||||
func (r *reader) readAllocationStats(d string) (a *AllocationStats) {
|
||||
// Create a reader for this subdirectory
|
||||
sr := &reader{path: path.Join(r.path, d), devCount: r.devCount}
|
||||
|
||||
// Get the stats
|
||||
a = &AllocationStats{
|
||||
// Read basic allocation stats
|
||||
MayUseBytes: sr.readValue("bytes_may_use"),
|
||||
PinnedBytes: sr.readValue("bytes_pinned"),
|
||||
ReadOnlyBytes: sr.readValue("bytes_readonly"),
|
||||
ReservedBytes: sr.readValue("bytes_reserved"),
|
||||
UsedBytes: sr.readValue("bytes_used"),
|
||||
DiskUsedBytes: sr.readValue("disk_used"),
|
||||
DiskTotalBytes: sr.readValue("disk_total"),
|
||||
Flags: sr.readValue("flags"),
|
||||
TotalBytes: sr.readValue("total_bytes"),
|
||||
TotalPinnedBytes: sr.readValue("total_bytes_pinned"),
|
||||
Layouts: sr.readLayouts(),
|
||||
}
|
||||
|
||||
// Pass any error back
|
||||
r.err = sr.err
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// readLayouts reads all Btrfs layout statistics for the current path
|
||||
func (r *reader) readLayouts() map[string]*LayoutUsage {
|
||||
files, err := ioutil.ReadDir(r.path)
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return nil
|
||||
}
|
||||
|
||||
m := make(map[string]*LayoutUsage)
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
m[f.Name()] = r.readLayout(f.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// readLayout reads the Btrfs layout statistics for an allocation layout.
|
||||
func (r *reader) readLayout(p string) (l *LayoutUsage) {
|
||||
l = new(LayoutUsage)
|
||||
l.TotalBytes = r.readValue(path.Join(p, "total_bytes"))
|
||||
l.UsedBytes = r.readValue(path.Join(p, "used_bytes"))
|
||||
l.Ratio = r.calcRatio(p)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// calcRatio returns the calculated ratio for a layout mode.
|
||||
func (r *reader) calcRatio(p string) float64 {
|
||||
switch p {
|
||||
case "single", "raid0":
|
||||
return 1
|
||||
case "dup", "raid1", "raid10":
|
||||
return 2
|
||||
case "raid5":
|
||||
return float64(r.devCount) / (float64(r.devCount) - 1)
|
||||
case "raid6":
|
||||
return float64(r.devCount) / (float64(r.devCount) - 2)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// readDeviceInfo returns the information for all devices associated with this filesystem.
|
||||
func (r *reader) readDeviceInfo(d string) map[string]*Device {
|
||||
devs := r.listFiles("devices")
|
||||
info := make(map[string]*Device, len(devs))
|
||||
for _, n := range devs {
|
||||
info[n] = &Device{
|
||||
Size: SectorSize * r.readValue("devices/"+n+"/size"),
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// readFilesystemStats reads Btrfs statistics for a filesystem.
|
||||
func (r *reader) readFilesystemStats() (s *Stats) {
|
||||
// First get disk info, and add it to reader
|
||||
devices := r.readDeviceInfo("devices")
|
||||
r.devCount = len(devices)
|
||||
|
||||
s = &Stats{
|
||||
// Read basic filesystem information
|
||||
Label: r.readFile("label"),
|
||||
UUID: r.readFile("metadata_uuid"),
|
||||
Features: r.listFiles("features"),
|
||||
CloneAlignment: r.readValue("clone_alignment"),
|
||||
NodeSize: r.readValue("nodesize"),
|
||||
QuotaOverride: r.readValue("quota_override"),
|
||||
SectorSize: r.readValue("sectorsize"),
|
||||
|
||||
// Device info
|
||||
Devices: devices,
|
||||
|
||||
// Read allocation data
|
||||
Allocation: Allocation{
|
||||
GlobalRsvReserved: r.readValue("allocation/global_rsv_reserved"),
|
||||
GlobalRsvSize: r.readValue("allocation/global_rsv_size"),
|
||||
Data: r.readAllocationStats("allocation/data"),
|
||||
Metadata: r.readAllocationStats("allocation/metadata"),
|
||||
System: r.readAllocationStats("allocation/system"),
|
||||
},
|
||||
}
|
||||
return
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue