github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/prometheus/procfs/xfs/parse.go (about)

     1  // Copyright 2017 The Prometheus Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package xfs
    15  
    16  import (
    17  	"bufio"
    18  	"fmt"
    19  	"io"
    20  	"strings"
    21  
    22  	"github.com/hellobchain/third_party/prometheus/procfs/internal/util"
    23  )
    24  
    25  // ParseStats parses a Stats from an input io.Reader, using the format
    26  // found in /proc/fs/xfs/stat.
    27  func ParseStats(r io.Reader) (*Stats, error) {
    28  	const (
    29  		// Fields parsed into stats structures.
    30  		fieldExtentAlloc = "extent_alloc"
    31  		fieldAbt         = "abt"
    32  		fieldBlkMap      = "blk_map"
    33  		fieldBmbt        = "bmbt"
    34  		fieldDir         = "dir"
    35  		fieldTrans       = "trans"
    36  		fieldIg          = "ig"
    37  		fieldLog         = "log"
    38  		fieldRw          = "rw"
    39  		fieldAttr        = "attr"
    40  		fieldIcluster    = "icluster"
    41  		fieldVnodes      = "vnodes"
    42  		fieldBuf         = "buf"
    43  		fieldXpc         = "xpc"
    44  
    45  		// Unimplemented at this time due to lack of documentation.
    46  		// fieldPushAil = "push_ail"
    47  		// fieldXstrat  = "xstrat"
    48  		// fieldAbtb2   = "abtb2"
    49  		// fieldAbtc2   = "abtc2"
    50  		// fieldBmbt2   = "bmbt2"
    51  		// fieldIbt2    = "ibt2"
    52  		// fieldFibt2   = "fibt2"
    53  		// fieldQm      = "qm"
    54  		// fieldDebug   = "debug"
    55  	)
    56  
    57  	var xfss Stats
    58  
    59  	s := bufio.NewScanner(r)
    60  	for s.Scan() {
    61  		// Expect at least a string label and a single integer value, ex:
    62  		//   - abt 0
    63  		//   - rw 1 2
    64  		ss := strings.Fields(string(s.Bytes()))
    65  		if len(ss) < 2 {
    66  			continue
    67  		}
    68  		label := ss[0]
    69  
    70  		// Extended precision counters are uint64 values.
    71  		if label == fieldXpc {
    72  			us, err := util.ParseUint64s(ss[1:])
    73  			if err != nil {
    74  				return nil, err
    75  			}
    76  
    77  			xfss.ExtendedPrecision, err = extendedPrecisionStats(us)
    78  			if err != nil {
    79  				return nil, err
    80  			}
    81  
    82  			continue
    83  		}
    84  
    85  		// All other counters are uint32 values.
    86  		us, err := util.ParseUint32s(ss[1:])
    87  		if err != nil {
    88  			return nil, err
    89  		}
    90  
    91  		switch label {
    92  		case fieldExtentAlloc:
    93  			xfss.ExtentAllocation, err = extentAllocationStats(us)
    94  		case fieldAbt:
    95  			xfss.AllocationBTree, err = btreeStats(us)
    96  		case fieldBlkMap:
    97  			xfss.BlockMapping, err = blockMappingStats(us)
    98  		case fieldBmbt:
    99  			xfss.BlockMapBTree, err = btreeStats(us)
   100  		case fieldDir:
   101  			xfss.DirectoryOperation, err = directoryOperationStats(us)
   102  		case fieldTrans:
   103  			xfss.Transaction, err = transactionStats(us)
   104  		case fieldIg:
   105  			xfss.InodeOperation, err = inodeOperationStats(us)
   106  		case fieldLog:
   107  			xfss.LogOperation, err = logOperationStats(us)
   108  		case fieldRw:
   109  			xfss.ReadWrite, err = readWriteStats(us)
   110  		case fieldAttr:
   111  			xfss.AttributeOperation, err = attributeOperationStats(us)
   112  		case fieldIcluster:
   113  			xfss.InodeClustering, err = inodeClusteringStats(us)
   114  		case fieldVnodes:
   115  			xfss.Vnode, err = vnodeStats(us)
   116  		case fieldBuf:
   117  			xfss.Buffer, err = bufferStats(us)
   118  		}
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  	}
   123  
   124  	return &xfss, s.Err()
   125  }
   126  
   127  // extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s.
   128  func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) {
   129  	if l := len(us); l != 4 {
   130  		return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l)
   131  	}
   132  
   133  	return ExtentAllocationStats{
   134  		ExtentsAllocated: us[0],
   135  		BlocksAllocated:  us[1],
   136  		ExtentsFreed:     us[2],
   137  		BlocksFreed:      us[3],
   138  	}, nil
   139  }
   140  
   141  // btreeStats builds a BTreeStats from a slice of uint32s.
   142  func btreeStats(us []uint32) (BTreeStats, error) {
   143  	if l := len(us); l != 4 {
   144  		return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l)
   145  	}
   146  
   147  	return BTreeStats{
   148  		Lookups:         us[0],
   149  		Compares:        us[1],
   150  		RecordsInserted: us[2],
   151  		RecordsDeleted:  us[3],
   152  	}, nil
   153  }
   154  
   155  // BlockMappingStat builds a BlockMappingStats from a slice of uint32s.
   156  func blockMappingStats(us []uint32) (BlockMappingStats, error) {
   157  	if l := len(us); l != 7 {
   158  		return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l)
   159  	}
   160  
   161  	return BlockMappingStats{
   162  		Reads:                us[0],
   163  		Writes:               us[1],
   164  		Unmaps:               us[2],
   165  		ExtentListInsertions: us[3],
   166  		ExtentListDeletions:  us[4],
   167  		ExtentListLookups:    us[5],
   168  		ExtentListCompares:   us[6],
   169  	}, nil
   170  }
   171  
   172  // DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s.
   173  func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) {
   174  	if l := len(us); l != 4 {
   175  		return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l)
   176  	}
   177  
   178  	return DirectoryOperationStats{
   179  		Lookups:  us[0],
   180  		Creates:  us[1],
   181  		Removes:  us[2],
   182  		Getdents: us[3],
   183  	}, nil
   184  }
   185  
   186  // TransactionStats builds a TransactionStats from a slice of uint32s.
   187  func transactionStats(us []uint32) (TransactionStats, error) {
   188  	if l := len(us); l != 3 {
   189  		return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l)
   190  	}
   191  
   192  	return TransactionStats{
   193  		Sync:  us[0],
   194  		Async: us[1],
   195  		Empty: us[2],
   196  	}, nil
   197  }
   198  
   199  // InodeOperationStats builds an InodeOperationStats from a slice of uint32s.
   200  func inodeOperationStats(us []uint32) (InodeOperationStats, error) {
   201  	if l := len(us); l != 7 {
   202  		return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l)
   203  	}
   204  
   205  	return InodeOperationStats{
   206  		Attempts:        us[0],
   207  		Found:           us[1],
   208  		Recycle:         us[2],
   209  		Missed:          us[3],
   210  		Duplicate:       us[4],
   211  		Reclaims:        us[5],
   212  		AttributeChange: us[6],
   213  	}, nil
   214  }
   215  
   216  // LogOperationStats builds a LogOperationStats from a slice of uint32s.
   217  func logOperationStats(us []uint32) (LogOperationStats, error) {
   218  	if l := len(us); l != 5 {
   219  		return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l)
   220  	}
   221  
   222  	return LogOperationStats{
   223  		Writes:            us[0],
   224  		Blocks:            us[1],
   225  		NoInternalBuffers: us[2],
   226  		Force:             us[3],
   227  		ForceSleep:        us[4],
   228  	}, nil
   229  }
   230  
   231  // ReadWriteStats builds a ReadWriteStats from a slice of uint32s.
   232  func readWriteStats(us []uint32) (ReadWriteStats, error) {
   233  	if l := len(us); l != 2 {
   234  		return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l)
   235  	}
   236  
   237  	return ReadWriteStats{
   238  		Read:  us[0],
   239  		Write: us[1],
   240  	}, nil
   241  }
   242  
   243  // AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s.
   244  func attributeOperationStats(us []uint32) (AttributeOperationStats, error) {
   245  	if l := len(us); l != 4 {
   246  		return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l)
   247  	}
   248  
   249  	return AttributeOperationStats{
   250  		Get:    us[0],
   251  		Set:    us[1],
   252  		Remove: us[2],
   253  		List:   us[3],
   254  	}, nil
   255  }
   256  
   257  // InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s.
   258  func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) {
   259  	if l := len(us); l != 3 {
   260  		return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l)
   261  	}
   262  
   263  	return InodeClusteringStats{
   264  		Iflush:     us[0],
   265  		Flush:      us[1],
   266  		FlushInode: us[2],
   267  	}, nil
   268  }
   269  
   270  // VnodeStats builds a VnodeStats from a slice of uint32s.
   271  func vnodeStats(us []uint32) (VnodeStats, error) {
   272  	// The attribute "Free" appears to not be available on older XFS
   273  	// stats versions.  Therefore, 7 or 8 elements may appear in
   274  	// this slice.
   275  	l := len(us)
   276  	if l != 7 && l != 8 {
   277  		return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l)
   278  	}
   279  
   280  	s := VnodeStats{
   281  		Active:   us[0],
   282  		Allocate: us[1],
   283  		Get:      us[2],
   284  		Hold:     us[3],
   285  		Release:  us[4],
   286  		Reclaim:  us[5],
   287  		Remove:   us[6],
   288  	}
   289  
   290  	// Skip adding free, unless it is present. The zero value will
   291  	// be used in place of an actual count.
   292  	if l == 7 {
   293  		return s, nil
   294  	}
   295  
   296  	s.Free = us[7]
   297  	return s, nil
   298  }
   299  
   300  // BufferStats builds a BufferStats from a slice of uint32s.
   301  func bufferStats(us []uint32) (BufferStats, error) {
   302  	if l := len(us); l != 9 {
   303  		return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l)
   304  	}
   305  
   306  	return BufferStats{
   307  		Get:             us[0],
   308  		Create:          us[1],
   309  		GetLocked:       us[2],
   310  		GetLockedWaited: us[3],
   311  		BusyLocked:      us[4],
   312  		MissLocked:      us[5],
   313  		PageRetries:     us[6],
   314  		PageFound:       us[7],
   315  		GetRead:         us[8],
   316  	}, nil
   317  }
   318  
   319  // ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s.
   320  func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) {
   321  	if l := len(us); l != 3 {
   322  		return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l)
   323  	}
   324  
   325  	return ExtendedPrecisionStats{
   326  		FlushBytes: us[0],
   327  		WriteBytes: us[1],
   328  		ReadBytes:  us[2],
   329  	}, nil
   330  }