| 87 | } |
| 88 | |
| 89 | func measureMetrics(targetFunc func()) (Metrics, error) { //nolint:unparam // make it extensible for future error handling |
| 90 | done := make(chan struct{}) |
| 91 | var cpuUsage []float64 |
| 92 | var memUsage []float64 |
| 93 | var startTime time.Time |
| 94 | var diskUsageBefore, diskUsageAfter uint64 |
| 95 | |
| 96 | wg := sync.WaitGroup{} |
| 97 | // Increment the WaitGroup counter by 1 to indicate that the main goroutine |
| 98 | // should wait for the target function (which runs in another goroutine) |
| 99 | // to complete its execution. The value 1 is used because there's only |
| 100 | // one goroutine running the target function. |
| 101 | wg.Add(1) |
| 102 | |
| 103 | go func() { |
| 104 | targetFunc() |
| 105 | done <- struct{}{} |
| 106 | }() |
| 107 | |
| 108 | go func() { |
| 109 | before, err := disk.Usage("/") |
| 110 | if err != nil { |
| 111 | logrus.Errorf("Error getting disk usage before: %v", err) |
| 112 | wg.Done() |
| 113 | return |
| 114 | } |
| 115 | diskUsageBefore = before.Free |
| 116 | |
| 117 | ticker := time.NewTicker(10 * time.Millisecond) |
| 118 | startTime = time.Now() |
| 119 | |
| 120 | for { |
| 121 | select { |
| 122 | case <-ticker.C: |
| 123 | percent, err := cpu.Percent(time.Millisecond*10, false) |
| 124 | if err != nil { |
| 125 | ticker.Stop() |
| 126 | wg.Done() |
| 127 | return |
| 128 | } |
| 129 | cpuUsage = append(cpuUsage, percent[0]) |
| 130 | |
| 131 | memStat, err := mem.VirtualMemory() |
| 132 | if err != nil { |
| 133 | ticker.Stop() |
| 134 | wg.Done() |
| 135 | return |
| 136 | } |
| 137 | memUsage = append(memUsage, memStat.UsedPercent) |
| 138 | case <-done: |
| 139 | |
| 140 | after, err := disk.Usage("/") |
| 141 | if err != nil { |
| 142 | logrus.Errorf("Error getting disk usage after: %v", err) |
| 143 | wg.Done() |
| 144 | return |
| 145 | } |
| 146 | diskUsageAfter = after.Free |