system_collector_macos.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //go:build darwin
  2. package diagnostic
  3. import (
  4. "context"
  5. "fmt"
  6. "os/exec"
  7. "runtime"
  8. "strconv"
  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, 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. var memoryMaximum, memoryCurrent, fileDescriptorMaximum, fileDescriptorCurrent uint64
  26. var osSystem, name, osVersion, osRelease, architecture string
  27. err := SystemInformationGeneralError{
  28. OperatingSystemInformationError: nil,
  29. MemoryInformationError: nil,
  30. FileDescriptorsInformationError: nil,
  31. DiskVolumeInformationError: nil,
  32. }
  33. if memoryInfoErr != nil {
  34. err.MemoryInformationError = SystemInformationError{
  35. Err: memoryInfoErr,
  36. RawInfo: memoryInfoRaw,
  37. }
  38. } else {
  39. memoryMaximum = memoryInfo.MemoryMaximum
  40. memoryCurrent = memoryInfo.MemoryCurrent
  41. }
  42. if fdInfoErr != nil {
  43. err.FileDescriptorsInformationError = SystemInformationError{
  44. Err: fdInfoErr,
  45. RawInfo: fdInfoRaw,
  46. }
  47. } else {
  48. fileDescriptorMaximum = fdInfo.FileDescriptorMaximum
  49. fileDescriptorCurrent = fdInfo.FileDescriptorCurrent
  50. }
  51. if diskErr != nil {
  52. err.DiskVolumeInformationError = SystemInformationError{
  53. Err: diskErr,
  54. RawInfo: disksRaw,
  55. }
  56. }
  57. if osInfoErr != nil {
  58. err.OperatingSystemInformationError = SystemInformationError{
  59. Err: osInfoErr,
  60. RawInfo: osInfoRaw,
  61. }
  62. } else {
  63. osSystem = osInfo.OsSystem
  64. name = osInfo.Name
  65. osVersion = osInfo.OsVersion
  66. osRelease = osInfo.OsRelease
  67. architecture = osInfo.Architecture
  68. }
  69. cloudflaredVersion := collector.version
  70. info := NewSystemInformation(
  71. memoryMaximum,
  72. memoryCurrent,
  73. fileDescriptorMaximum,
  74. fileDescriptorCurrent,
  75. osSystem,
  76. name,
  77. osVersion,
  78. osRelease,
  79. architecture,
  80. cloudflaredVersion,
  81. runtime.Version(),
  82. runtime.GOARCH,
  83. disks,
  84. )
  85. return info, err
  86. }
  87. func collectFileDescriptorInformation(ctx context.Context) (
  88. *FileDescriptorInformation,
  89. string,
  90. error,
  91. ) {
  92. const (
  93. fileDescriptorMaximumKey = "kern.maxfiles"
  94. fileDescriptorCurrentKey = "kern.num_files"
  95. )
  96. command := exec.CommandContext(ctx, "sysctl", fileDescriptorMaximumKey, fileDescriptorCurrentKey)
  97. stdout, err := command.Output()
  98. if err != nil {
  99. return nil, "", fmt.Errorf("error retrieving output from command '%s': %w", command.String(), err)
  100. }
  101. output := string(stdout)
  102. fileDescriptorInfo, err := ParseFileDescriptorInformationFromKV(
  103. output,
  104. fileDescriptorMaximumKey,
  105. fileDescriptorCurrentKey,
  106. )
  107. if err != nil {
  108. return nil, output, err
  109. }
  110. // returning raw output in case other collected information
  111. // resulted in errors
  112. return fileDescriptorInfo, output, nil
  113. }
  114. func collectMemoryInformation(ctx context.Context) (
  115. *MemoryInformation,
  116. string,
  117. error,
  118. ) {
  119. const (
  120. memoryMaximumKey = "hw.memsize"
  121. memoryAvailableKey = "hw.memsize_usable"
  122. )
  123. command := exec.CommandContext(
  124. ctx,
  125. "sysctl",
  126. memoryMaximumKey,
  127. memoryAvailableKey,
  128. )
  129. stdout, err := command.Output()
  130. if err != nil {
  131. return nil, "", fmt.Errorf("error retrieving output from command '%s': %w", command.String(), err)
  132. }
  133. output := string(stdout)
  134. mapper := func(field string) (uint64, error) {
  135. const kiloBytes = 1024
  136. value, err := strconv.ParseUint(field, 10, 64)
  137. return value / kiloBytes, err
  138. }
  139. memoryInfo, err := ParseMemoryInformationFromKV(output, memoryMaximumKey, memoryAvailableKey, mapper)
  140. if err != nil {
  141. return nil, output, err
  142. }
  143. // returning raw output in case other collected information
  144. // resulted in errors
  145. return memoryInfo, output, nil
  146. }