system_collector_linux.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. //go:build linux
  2. package diagnostic
  3. import (
  4. "context"
  5. "fmt"
  6. "os/exec"
  7. "strconv"
  8. "strings"
  9. )
  10. type SystemCollectorImpl struct {
  11. version string
  12. }
  13. func NewSystemCollectorImpl(
  14. version string,
  15. ) *SystemCollectorImpl {
  16. return &SystemCollectorImpl{
  17. version,
  18. }
  19. }
  20. func (collector *SystemCollectorImpl) Collect(ctx context.Context) (*SystemInformation, string, error) {
  21. memoryInfo, memoryInfoRaw, memoryInfoErr := collectMemoryInformation(ctx)
  22. fdInfo, fdInfoRaw, fdInfoErr := collectFileDescriptorInformation(ctx)
  23. disks, disksRaw, diskErr := collectDiskVolumeInformationUnix(ctx)
  24. osInfo, osInfoRaw, osInfoErr := collectOSInformationUnix(ctx)
  25. if memoryInfoErr != nil {
  26. raw := RawSystemInformation(osInfoRaw, memoryInfoRaw, fdInfoRaw, disksRaw)
  27. return nil, raw, memoryInfoErr
  28. }
  29. if fdInfoErr != nil {
  30. raw := RawSystemInformation(osInfoRaw, memoryInfoRaw, fdInfoRaw, disksRaw)
  31. return nil, raw, fdInfoErr
  32. }
  33. if diskErr != nil {
  34. raw := RawSystemInformation(osInfoRaw, memoryInfoRaw, fdInfoRaw, disksRaw)
  35. return nil, raw, diskErr
  36. }
  37. if osInfoErr != nil {
  38. raw := RawSystemInformation(osInfoRaw, memoryInfoRaw, fdInfoRaw, disksRaw)
  39. return nil, raw, osInfoErr
  40. }
  41. return NewSystemInformation(
  42. memoryInfo.MemoryMaximum,
  43. memoryInfo.MemoryCurrent,
  44. fdInfo.FileDescriptorMaximum,
  45. fdInfo.FileDescriptorCurrent,
  46. osInfo.OsSystem,
  47. osInfo.Name,
  48. osInfo.OsVersion,
  49. osInfo.OsRelease,
  50. osInfo.Architecture,
  51. collector.version,
  52. disks,
  53. ), "", nil
  54. }
  55. func collectMemoryInformation(ctx context.Context) (*MemoryInformation, string, error) {
  56. // This function relies on the output of `cat /proc/meminfo` to retrieve
  57. // memoryMax and memoryCurrent.
  58. // The expected output is in the format of `KEY VALUE UNIT`.
  59. const (
  60. memTotalPrefix = "MemTotal"
  61. memAvailablePrefix = "MemAvailable"
  62. )
  63. command := exec.CommandContext(ctx, "cat", "/proc/meminfo")
  64. stdout, err := command.Output()
  65. if err != nil {
  66. return nil, "", fmt.Errorf("error retrieving output from command '%s': %w", command.String(), err)
  67. }
  68. output := string(stdout)
  69. mapper := func(field string) (uint64, error) {
  70. field = strings.TrimRight(field, " kB")
  71. return strconv.ParseUint(field, 10, 64)
  72. }
  73. memoryInfo, err := ParseMemoryInformationFromKV(output, memTotalPrefix, memAvailablePrefix, mapper)
  74. if err != nil {
  75. return nil, output, err
  76. }
  77. // returning raw output in case other collected information
  78. // resulted in errors
  79. return memoryInfo, output, nil
  80. }
  81. func collectFileDescriptorInformation(ctx context.Context) (*FileDescriptorInformation, string, error) {
  82. // Command retrieved from https://docs.kernel.org/admin-guide/sysctl/fs.html#file-max-file-nr.
  83. // If the sysctl is not available the command with fail.
  84. command := exec.CommandContext(ctx, "sysctl", "-n", "fs.file-nr")
  85. stdout, err := command.Output()
  86. if err != nil {
  87. return nil, "", fmt.Errorf("error retrieving output from command '%s': %w", command.String(), err)
  88. }
  89. output := string(stdout)
  90. fileDescriptorInfo, err := ParseSysctlFileDescriptorInformation(output)
  91. if err != nil {
  92. return nil, output, err
  93. }
  94. // returning raw output in case other collected information
  95. // resulted in errors
  96. return fileDescriptorInfo, output, nil
  97. }