Skip to content

Commit 52ffd69

Browse files
committed
FIX-51-refactored the code.
1 parent e19a589 commit 52ffd69

File tree

4 files changed

+122
-1
lines changed

4 files changed

+122
-1
lines changed

cmd/capture/main.go

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ func main() {
5050
apiV1.GET("/metrics/memory", handler.MetricsMemory)
5151
apiV1.GET("/metrics/disk", handler.MetricsDisk)
5252
apiV1.GET("/metrics/host", handler.MetricsHost)
53+
apiV1.GET("/metrics/smartmetrics", handler.SmartMetrics)
54+
5355

5456
server := &http.Server{
5557
Addr: ":" + appConfig.Port,

internal/handler/metrics.go

+5
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,8 @@ func MetricsHost(c *gin.Context) {
4040
hostMetrics, metricsErrs := metric.GetHostInformation()
4141
handleMetricResponse(c, hostMetrics, metricsErrs)
4242
}
43+
44+
func SmartMetrics(c *gin.Context) {
45+
smartMetrics, smartErrs := metric.GetSmartMetrics() // Returns []*SmartMetric
46+
handleMetricResponse(c, smartMetrics, smartErrs)
47+
}

internal/metric/metric.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ type APIResponse struct {
1313
Errors []CustomErr `json:"errors"`
1414
}
1515

16+
type SmartMetric struct {
17+
Data map[string]string `json:"data"`
18+
Errors []CustomErr `json:"errors"`
19+
}
20+
21+
func (s SmartMetric) isMetric() {}
22+
1623
type AllMetrics struct {
1724
CPU CPUData `json:"cpu"`
1825
Memory MemoryData `json:"memory"`
@@ -95,4 +102,4 @@ func GetAllSystemMetrics() (AllMetrics, []CustomErr) {
95102
Disk: disk,
96103
Host: *host,
97104
}, errors
98-
}
105+
}

internal/metric/smart_metrics.go

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package metric
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"os/exec"
7+
"regexp"
8+
"strings"
9+
)
10+
11+
// scanDevices returns a list of disks using `smartctl --scan`
12+
func scanDevices() ([]string, error) {
13+
out, err := exec.Command("smartctl", "--scan").Output()
14+
if err != nil {
15+
return nil, fmt.Errorf("failed to scan devices: %v", err)
16+
}
17+
18+
var devices []string
19+
lines := strings.Split(string(out), "\n")
20+
for _, line := range lines {
21+
fields := strings.Fields(line)
22+
if len(fields) > 0 {
23+
devices = append(devices, fields[0])
24+
}
25+
}
26+
return devices, nil
27+
}
28+
29+
func parseSmartctlOutput(output string) *SmartMetric {
30+
startMarker := "=== START OF SMART DATA SECTION ==="
31+
startIdx := strings.Index(output, startMarker)
32+
if startIdx == -1 {
33+
return &SmartMetric{Data: make(map[string]string)}
34+
}
35+
36+
section := output[startIdx:]
37+
endIdx := strings.Index(section, "===")
38+
if endIdx > len(startMarker) {
39+
section = section[:endIdx]
40+
}
41+
42+
data := make(map[string]string)
43+
lines := strings.Split(section, "\n")
44+
45+
for _, line := range lines {
46+
if strings.TrimSpace(line) == "" || strings.HasPrefix(line, "===") {
47+
continue
48+
}
49+
50+
// Split into key/value pairs
51+
parts := strings.SplitN(line, ":", 2)
52+
if len(parts) != 2 {
53+
continue
54+
}
55+
56+
key := strings.TrimSpace(parts[0])
57+
value := strings.TrimSpace(parts[1])
58+
59+
// Clean up value: remove extra spaces and brackets
60+
value = regexp.MustCompile(`\s+`).ReplaceAllString(value, " ")
61+
value = strings.Trim(value, "[]")
62+
63+
data[key] = value
64+
}
65+
66+
return &SmartMetric{
67+
Data: data,
68+
}
69+
}
70+
71+
func getMetrics(device string) (*SmartMetric, error) {
72+
cmd := exec.Command("smartctl", "-d", "nvme", "--xall", "--nocheck", "standby", device)
73+
out, err := cmd.CombinedOutput()
74+
75+
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 4 {
76+
err = nil
77+
}
78+
79+
if err != nil {
80+
return nil, fmt.Errorf("smartctl failed: %v", err)
81+
}
82+
83+
return parseSmartctlOutput(string(out)), nil
84+
}
85+
86+
func GetSmartMetrics() (MetricsSlice, []CustomErr) {
87+
var smartCtlrErrs []CustomErr
88+
devices, err := scanDevices()
89+
if err != nil {
90+
smartCtlrErrs =append(smartCtlrErrs,CustomErr{
91+
Metric: []string{"smart"},
92+
Error: err.Error(),
93+
})
94+
}
95+
96+
var metrics MetricsSlice // Use MetricsSlice instead of []*SmartMetric
97+
for _, device := range devices {
98+
metric, err := getMetrics(device)
99+
if err != nil {
100+
log.Printf("Skipping %s: %v", device, err)
101+
continue
102+
}
103+
metrics = append(metrics, metric)
104+
}
105+
106+
return metrics, smartCtlrErrs
107+
}

0 commit comments

Comments
 (0)