Node_Exporter/vendor/github.com/prometheus/procfs/xfs/parse.go
Paul Gier 0b7ac85acb update procfs to v0.0.4 (#1457)
Signed-off-by: Paul Gier <pgier@redhat.com>
2019-08-27 09:26:19 +02:00

509 lines
13 KiB
Go

// Copyright 2017 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 xfs
import (
"bufio"
"fmt"
"io"
"strings"
"github.com/prometheus/procfs/internal/util"
)
// ParseStats parses a Stats from an input io.Reader, using the format
// found in /proc/fs/xfs/stat.
func ParseStats(r io.Reader) (*Stats, error) {
const (
// Fields parsed into stats structures.
fieldExtentAlloc = "extent_alloc"
fieldAbt = "abt"
fieldBlkMap = "blk_map"
fieldBmbt = "bmbt"
fieldDir = "dir"
fieldTrans = "trans"
fieldIg = "ig"
fieldLog = "log"
fieldPushAil = "push_ail"
fieldXstrat = "xstrat"
fieldRw = "rw"
fieldAttr = "attr"
fieldIcluster = "icluster"
fieldVnodes = "vnodes"
fieldBuf = "buf"
fieldXpc = "xpc"
fieldAbtb2 = "abtb2"
fieldAbtc2 = "abtc2"
fieldBmbt2 = "bmbt2"
fieldIbt2 = "ibt2"
//fieldFibt2 = "fibt2"
fieldQm = "qm"
fieldDebug = "debug"
// Unimplemented at this time due to lack of documentation.
//fieldRmapbt = "rmapbt"
//fieldRefcntbt = "refcntbt"
)
var xfss Stats
s := bufio.NewScanner(r)
for s.Scan() {
// Expect at least a string label and a single integer value, ex:
// - abt 0
// - rw 1 2
ss := strings.Fields(string(s.Bytes()))
if len(ss) < 2 {
continue
}
label := ss[0]
// Extended precision counters are uint64 values.
if label == fieldXpc {
us, err := util.ParseUint64s(ss[1:])
if err != nil {
return nil, err
}
xfss.ExtendedPrecision, err = extendedPrecisionStats(us)
if err != nil {
return nil, err
}
continue
}
// All other counters are uint32 values.
us, err := util.ParseUint32s(ss[1:])
if err != nil {
return nil, err
}
switch label {
case fieldExtentAlloc:
xfss.ExtentAllocation, err = extentAllocationStats(us)
case fieldAbt:
xfss.AllocationBTree, err = btreeStats(us)
case fieldBlkMap:
xfss.BlockMapping, err = blockMappingStats(us)
case fieldBmbt:
xfss.BlockMapBTree, err = btreeStats(us)
case fieldDir:
xfss.DirectoryOperation, err = directoryOperationStats(us)
case fieldTrans:
xfss.Transaction, err = transactionStats(us)
case fieldIg:
xfss.InodeOperation, err = inodeOperationStats(us)
case fieldLog:
xfss.LogOperation, err = logOperationStats(us)
case fieldRw:
xfss.ReadWrite, err = readWriteStats(us)
case fieldAttr:
xfss.AttributeOperation, err = attributeOperationStats(us)
case fieldIcluster:
xfss.InodeClustering, err = inodeClusteringStats(us)
case fieldVnodes:
xfss.Vnode, err = vnodeStats(us)
case fieldBuf:
xfss.Buffer, err = bufferStats(us)
case fieldPushAil:
xfss.PushAil, err = pushAilStats(us)
case fieldXstrat:
xfss.Xstrat, err = xStratStats(us)
case fieldAbtb2:
xfss.BtreeAllocBlocks2, err = btreeAllocBlocks2Stats(us)
case fieldAbtc2:
xfss.BtreeAllocContig2, err = btreeAllocContig2Stats(us)
case fieldBmbt2:
xfss.BtreeBlockMap2, err = btreeBlockMap2Stats(us)
case fieldIbt2:
xfss.BtreeInode2, err = btreeInode2Stats(us)
//case fieldFibt2:
case fieldQm:
xfss.QuotaManager, err = quotaManagerStats(us)
case fieldDebug:
xfss.Debug, err = debugStats(us)
}
if err != nil {
return nil, err
}
}
return &xfss, s.Err()
}
// extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s.
func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) {
if l := len(us); l != 4 {
return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l)
}
return ExtentAllocationStats{
ExtentsAllocated: us[0],
BlocksAllocated: us[1],
ExtentsFreed: us[2],
BlocksFreed: us[3],
}, nil
}
// btreeStats builds a BTreeStats from a slice of uint32s.
func btreeStats(us []uint32) (BTreeStats, error) {
if l := len(us); l != 4 {
return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l)
}
return BTreeStats{
Lookups: us[0],
Compares: us[1],
RecordsInserted: us[2],
RecordsDeleted: us[3],
}, nil
}
// BlockMappingStat builds a BlockMappingStats from a slice of uint32s.
func blockMappingStats(us []uint32) (BlockMappingStats, error) {
if l := len(us); l != 7 {
return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l)
}
return BlockMappingStats{
Reads: us[0],
Writes: us[1],
Unmaps: us[2],
ExtentListInsertions: us[3],
ExtentListDeletions: us[4],
ExtentListLookups: us[5],
ExtentListCompares: us[6],
}, nil
}
// DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s.
func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) {
if l := len(us); l != 4 {
return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l)
}
return DirectoryOperationStats{
Lookups: us[0],
Creates: us[1],
Removes: us[2],
Getdents: us[3],
}, nil
}
// TransactionStats builds a TransactionStats from a slice of uint32s.
func transactionStats(us []uint32) (TransactionStats, error) {
if l := len(us); l != 3 {
return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l)
}
return TransactionStats{
Sync: us[0],
Async: us[1],
Empty: us[2],
}, nil
}
// InodeOperationStats builds an InodeOperationStats from a slice of uint32s.
func inodeOperationStats(us []uint32) (InodeOperationStats, error) {
if l := len(us); l != 7 {
return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l)
}
return InodeOperationStats{
Attempts: us[0],
Found: us[1],
Recycle: us[2],
Missed: us[3],
Duplicate: us[4],
Reclaims: us[5],
AttributeChange: us[6],
}, nil
}
// LogOperationStats builds a LogOperationStats from a slice of uint32s.
func logOperationStats(us []uint32) (LogOperationStats, error) {
if l := len(us); l != 5 {
return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l)
}
return LogOperationStats{
Writes: us[0],
Blocks: us[1],
NoInternalBuffers: us[2],
Force: us[3],
ForceSleep: us[4],
}, nil
}
// push_ail
func pushAilStats(us []uint32) (PushAilStats, error) {
if l := len(us); l != 10 {
return PushAilStats{}, fmt.Errorf("incorrect number of values for XFS push ail stats: %d", l)
}
return PushAilStats{
TryLogspace: us[0],
SleepLogspace: us[1],
Pushes: us[2],
Success: us[3],
PushBuf: us[4],
Pinned: us[5],
Locked: us[6],
Flushing: us[7],
Restarts: us[8],
Flush: us[9],
}, nil
}
// xstrat
func xStratStats(us []uint32) (XstratStats, error) {
if l := len(us); l != 2 {
return XstratStats{}, fmt.Errorf("incorrect number of values for XFS xstrat stats: %d", l)
}
return XstratStats{
Quick: us[0],
Split: us[1],
}, nil
}
// rw
func readWriteStats(us []uint32) (ReadWriteStats, error) {
if l := len(us); l != 2 {
return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l)
}
return ReadWriteStats{
Read: us[0],
Write: us[1],
}, nil
}
// AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s.
func attributeOperationStats(us []uint32) (AttributeOperationStats, error) {
if l := len(us); l != 4 {
return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l)
}
return AttributeOperationStats{
Get: us[0],
Set: us[1],
Remove: us[2],
List: us[3],
}, nil
}
// InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s.
func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) {
if l := len(us); l != 3 {
return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l)
}
return InodeClusteringStats{
Iflush: us[0],
Flush: us[1],
FlushInode: us[2],
}, nil
}
// VnodeStats builds a VnodeStats from a slice of uint32s.
func vnodeStats(us []uint32) (VnodeStats, error) {
// The attribute "Free" appears to not be available on older XFS
// stats versions. Therefore, 7 or 8 elements may appear in
// this slice.
l := len(us)
if l != 7 && l != 8 {
return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l)
}
s := VnodeStats{
Active: us[0],
Allocate: us[1],
Get: us[2],
Hold: us[3],
Release: us[4],
Reclaim: us[5],
Remove: us[6],
}
// Skip adding free, unless it is present. The zero value will
// be used in place of an actual count.
if l == 7 {
return s, nil
}
s.Free = us[7]
return s, nil
}
// BufferStats builds a BufferStats from a slice of uint32s.
func bufferStats(us []uint32) (BufferStats, error) {
if l := len(us); l != 9 {
return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l)
}
return BufferStats{
Get: us[0],
Create: us[1],
GetLocked: us[2],
GetLockedWaited: us[3],
BusyLocked: us[4],
MissLocked: us[5],
PageRetries: us[6],
PageFound: us[7],
GetRead: us[8],
}, nil
}
// ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s.
func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) {
if l := len(us); l != 3 {
return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l)
}
return ExtendedPrecisionStats{
FlushBytes: us[0],
WriteBytes: us[1],
ReadBytes: us[2],
}, nil
}
func quotaManagerStats(us []uint32) (QuotaManagerStats, error) {
if l := len(us); l != 8 {
return QuotaManagerStats{}, fmt.Errorf("incorrect number of values for XFS quota stats: %d", l)
}
return QuotaManagerStats{
Reclaims: us[0],
ReclaimMisses: us[1],
DquoteDups: us[2],
CacheMisses: us[3],
CacheHits: us[4],
Wants: us[5],
ShakeReclaims: us[6],
InactReclaims: us[7],
}, nil
}
func debugStats(us []uint32) (DebugStats, error) {
if l := len(us); l != 1 {
return DebugStats{}, fmt.Errorf("incorrect number of values for XFS debug stats: %d", l)
}
return DebugStats{
Enabled: us[0],
}, nil
}
// abtb2
func btreeAllocBlocks2Stats(us []uint32) (BtreeAllocBlocks2Stats, error) {
if l := len(us); l != 15 {
return BtreeAllocBlocks2Stats{}, fmt.Errorf("incorrect number of values for abtb2 stats: %d", 1)
}
return BtreeAllocBlocks2Stats{
Lookup: us[0],
Compare: us[1],
Insrec: us[2],
Delrec: us[3],
NewRoot: us[4],
KillRoot: us[5],
Increment: us[6],
Decrement: us[7],
Lshift: us[8],
Rshift: us[9],
Split: us[10],
Join: us[11],
Alloc: us[12],
Free: us[13],
Moves: us[14],
}, nil
}
// abtc2
func btreeAllocContig2Stats(us []uint32) (BtreeAllocContig2Stats, error) {
if l := len(us); l != 15 {
return BtreeAllocContig2Stats{}, fmt.Errorf("incorrect number of values for abtc2 stats: %d", 1)
}
return BtreeAllocContig2Stats{
Lookup: us[0],
Compare: us[1],
Insrec: us[2],
Delrec: us[3],
NewRoot: us[4],
KillRoot: us[5],
Increment: us[6],
Decrement: us[7],
Lshift: us[8],
Rshift: us[9],
Split: us[10],
Join: us[11],
Alloc: us[12],
Free: us[13],
Moves: us[14],
}, nil
}
// bmbt2
func btreeBlockMap2Stats(us []uint32) (BtreeBlockMap2Stats, error) {
if l := len(us); l != 15 {
return BtreeBlockMap2Stats{}, fmt.Errorf("incorrect number of values for bmbt2 stats: %d", 1)
}
return BtreeBlockMap2Stats{
Lookup: us[0],
Compare: us[1],
Insrec: us[2],
Delrec: us[3],
NewRoot: us[4],
KillRoot: us[5],
Increment: us[6],
Decrement: us[7],
Lshift: us[8],
Rshift: us[9],
Split: us[10],
Join: us[11],
Alloc: us[12],
Free: us[13],
Moves: us[14],
}, nil
}
// ibt2
func btreeInode2Stats(us []uint32) (BtreeInode2Stats, error) {
if l := len(us); l != 15 {
return BtreeInode2Stats{}, fmt.Errorf("incorrect number of values for ibt2 stats: %d", 1)
}
return BtreeInode2Stats{
Lookup: us[0],
Compare: us[1],
Insrec: us[2],
Delrec: us[3],
NewRoot: us[4],
KillRoot: us[5],
Increment: us[6],
Decrement: us[7],
Lshift: us[8],
Rshift: us[9],
Split: us[10],
Join: us[11],
Alloc: us[12],
Free: us[13],
Moves: us[14],
}, nil
}