stat.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package analytic
  2. import (
  3. "fmt"
  4. "math"
  5. "github.com/dustin/go-humanize"
  6. "github.com/pkg/errors"
  7. "github.com/shirou/gopsutil/v4/disk"
  8. "github.com/shirou/gopsutil/v4/mem"
  9. "github.com/spf13/cast"
  10. )
  11. type MemStat struct {
  12. Total string `json:"total"`
  13. Used string `json:"used"`
  14. Cached string `json:"cached"`
  15. Free string `json:"free"`
  16. SwapUsed string `json:"swap_used"`
  17. SwapTotal string `json:"swap_total"`
  18. SwapCached string `json:"swap_cached"`
  19. SwapPercent float64 `json:"swap_percent"`
  20. Pressure float64 `json:"pressure"`
  21. }
  22. type PartitionStat struct {
  23. Mountpoint string `json:"mountpoint"`
  24. Device string `json:"device"`
  25. Fstype string `json:"fstype"`
  26. Total string `json:"total"`
  27. Used string `json:"used"`
  28. Free string `json:"free"`
  29. Percentage float64 `json:"percentage"`
  30. }
  31. type DiskStat struct {
  32. Total string `json:"total"`
  33. Used string `json:"used"`
  34. Percentage float64 `json:"percentage"`
  35. Writes Usage[uint64] `json:"writes"`
  36. Reads Usage[uint64] `json:"reads"`
  37. Partitions []PartitionStat `json:"partitions"`
  38. }
  39. func GetMemoryStat() (MemStat, error) {
  40. memoryStat, err := mem.VirtualMemory()
  41. if err != nil {
  42. return MemStat{}, errors.Wrap(err, "error analytic getMemoryStat")
  43. }
  44. return MemStat{
  45. Total: humanize.Bytes(memoryStat.Total),
  46. Used: humanize.Bytes(memoryStat.Used),
  47. Cached: humanize.Bytes(memoryStat.Cached),
  48. Free: humanize.Bytes(memoryStat.Free),
  49. SwapUsed: humanize.Bytes(memoryStat.SwapTotal - memoryStat.SwapFree),
  50. SwapTotal: humanize.Bytes(memoryStat.SwapTotal),
  51. SwapCached: humanize.Bytes(memoryStat.SwapCached),
  52. SwapPercent: cast.ToFloat64(fmt.Sprintf("%.2f",
  53. 100*float64(memoryStat.SwapTotal-memoryStat.SwapFree)/math.Max(float64(memoryStat.SwapTotal), 1))),
  54. Pressure: cast.ToFloat64(fmt.Sprintf("%.2f", memoryStat.UsedPercent)),
  55. }, nil
  56. }
  57. func GetDiskStat() (DiskStat, error) {
  58. // Get all partitions
  59. partitions, err := disk.Partitions(false)
  60. if err != nil {
  61. return DiskStat{}, errors.Wrap(err, "error analytic getDiskStat - getting partitions")
  62. }
  63. var totalSize uint64
  64. var totalUsed uint64
  65. var partitionStats []PartitionStat
  66. // Get usage for each partition
  67. for _, partition := range partitions {
  68. usage, err := disk.Usage(partition.Mountpoint)
  69. if err != nil {
  70. // Skip partitions that can't be accessed
  71. continue
  72. }
  73. // Skip virtual filesystems and special filesystems
  74. if isVirtualFilesystem(partition.Fstype) {
  75. continue
  76. }
  77. partitionStat := PartitionStat{
  78. Mountpoint: partition.Mountpoint,
  79. Device: partition.Device,
  80. Fstype: partition.Fstype,
  81. Total: humanize.Bytes(usage.Total),
  82. Used: humanize.Bytes(usage.Used),
  83. Free: humanize.Bytes(usage.Free),
  84. Percentage: cast.ToFloat64(fmt.Sprintf("%.2f", usage.UsedPercent)),
  85. }
  86. partitionStats = append(partitionStats, partitionStat)
  87. totalSize += usage.Total
  88. totalUsed += usage.Used
  89. }
  90. // Calculate overall percentage
  91. var overallPercentage float64
  92. if totalSize > 0 {
  93. overallPercentage = cast.ToFloat64(fmt.Sprintf("%.2f", float64(totalUsed)/float64(totalSize)*100))
  94. }
  95. return DiskStat{
  96. Used: humanize.Bytes(totalUsed),
  97. Total: humanize.Bytes(totalSize),
  98. Percentage: overallPercentage,
  99. Writes: DiskWriteRecord[len(DiskWriteRecord)-1],
  100. Reads: DiskReadRecord[len(DiskReadRecord)-1],
  101. Partitions: partitionStats,
  102. }, nil
  103. }
  104. // isVirtualFilesystem checks if the filesystem type is virtual
  105. func isVirtualFilesystem(fstype string) bool {
  106. virtualFSTypes := map[string]bool{
  107. "proc": true,
  108. "sysfs": true,
  109. "devfs": true,
  110. "devpts": true,
  111. "tmpfs": true,
  112. "debugfs": true,
  113. "securityfs": true,
  114. "cgroup": true,
  115. "cgroup2": true,
  116. "pstore": true,
  117. "bpf": true,
  118. "tracefs": true,
  119. "hugetlbfs": true,
  120. "mqueue": true,
  121. "overlay": true,
  122. "autofs": true,
  123. "binfmt_misc": true,
  124. "configfs": true,
  125. "fusectl": true,
  126. "rpc_pipefs": true,
  127. "selinuxfs": true,
  128. "systemd-1": true,
  129. "none": true,
  130. }
  131. return virtualFSTypes[fstype]
  132. }