github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/load/load_linux.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package load
     5  
     6  import (
     7  	"context"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  	"syscall"
    12  
    13  	"github.com/gofiber/fiber/v2/internal/gopsutil/common"
    14  )
    15  
    16  func Avg() (*AvgStat, error) {
    17  	return AvgWithContext(context.Background())
    18  }
    19  
    20  func AvgWithContext(ctx context.Context) (*AvgStat, error) {
    21  	stat, err := fileAvgWithContext(ctx)
    22  	if err != nil {
    23  		stat, err = sysinfoAvgWithContext(ctx)
    24  	}
    25  	return stat, err
    26  }
    27  
    28  func sysinfoAvgWithContext(ctx context.Context) (*AvgStat, error) {
    29  	var info syscall.Sysinfo_t
    30  	err := syscall.Sysinfo(&info)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	const si_load_shift = 16
    36  	return &AvgStat{
    37  		Load1:  float64(info.Loads[0]) / float64(1<<si_load_shift),
    38  		Load5:  float64(info.Loads[1]) / float64(1<<si_load_shift),
    39  		Load15: float64(info.Loads[2]) / float64(1<<si_load_shift),
    40  	}, nil
    41  }
    42  
    43  func fileAvgWithContext(ctx context.Context) (*AvgStat, error) {
    44  	values, err := readLoadAvgFromFile()
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	load1, err := strconv.ParseFloat(values[0], 64)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	load5, err := strconv.ParseFloat(values[1], 64)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	load15, err := strconv.ParseFloat(values[2], 64)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	ret := &AvgStat{
    63  		Load1:  load1,
    64  		Load5:  load5,
    65  		Load15: load15,
    66  	}
    67  
    68  	return ret, nil
    69  }
    70  
    71  // Misc returnes miscellaneous host-wide statistics.
    72  // Note: the name should be changed near future.
    73  func Misc() (*MiscStat, error) {
    74  	return MiscWithContext(context.Background())
    75  }
    76  
    77  func MiscWithContext(ctx context.Context) (*MiscStat, error) {
    78  	filename := common.HostProc("stat")
    79  	out, err := os.ReadFile(filename)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	ret := &MiscStat{}
    85  	lines := strings.Split(string(out), "\n")
    86  	for _, line := range lines {
    87  		fields := strings.Fields(line)
    88  		if len(fields) != 2 {
    89  			continue
    90  		}
    91  		v, err := strconv.ParseInt(fields[1], 10, 64)
    92  		if err != nil {
    93  			continue
    94  		}
    95  		switch fields[0] {
    96  		case "processes":
    97  			ret.ProcsCreated = v
    98  		case "procs_running":
    99  			ret.ProcsRunning = v
   100  		case "procs_blocked":
   101  			ret.ProcsBlocked = v
   102  		case "ctxt":
   103  			ret.Ctxt = v
   104  		default:
   105  			continue
   106  		}
   107  
   108  	}
   109  
   110  	procsTotal, err := getProcsTotal()
   111  	if err != nil {
   112  		return ret, err
   113  	}
   114  	ret.ProcsTotal = procsTotal
   115  
   116  	return ret, nil
   117  }
   118  
   119  func getProcsTotal() (int64, error) {
   120  	values, err := readLoadAvgFromFile()
   121  	if err != nil {
   122  		return 0, err
   123  	}
   124  	return strconv.ParseInt(strings.Split(values[3], "/")[1], 10, 64)
   125  }
   126  
   127  func readLoadAvgFromFile() ([]string, error) {
   128  	loadavgFilename := common.HostProc("loadavg")
   129  	line, err := os.ReadFile(loadavgFilename)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	values := strings.Fields(string(line))
   135  	return values, nil
   136  }