@@ -32,6 +32,17 @@ type JSONCache struct {
32
32
LastCollect time.Time
33
33
}
34
34
35
+ type SMARTresult struct {
36
+ device Device
37
+ JSON gjson.Result
38
+ ok bool
39
+ }
40
+
41
+ type SMARTctlWorkerPool struct {
42
+ results chan SMARTresult
43
+ expected int
44
+ }
45
+
35
46
var (
36
47
jsonCache sync.Map
37
48
)
@@ -40,6 +51,10 @@ func init() {
40
51
jsonCache .Store ("" , JSONCache {})
41
52
}
42
53
54
+ func createPool () SMARTctlWorkerPool {
55
+ return SMARTctlWorkerPool {make (chan SMARTresult ), 0 }
56
+ }
57
+
43
58
// Parse json to gjson object
44
59
func parseJSON (data string ) gjson.Result {
45
60
if ! gjson .Valid (data ) {
@@ -62,7 +77,7 @@ func readFakeSMARTctl(logger log.Logger, device Device) gjson.Result {
62
77
}
63
78
64
79
// Get json from smartctl and parse it
65
- func readSMARTctl (logger log.Logger , device Device ) (gjson. Result , bool ) {
80
+ func readSMARTctl (logger log.Logger , device Device , results chan <- SMARTresult ) {
66
81
start := time .Now ()
67
82
out , err := exec .Command (* smartctlPath , "--json" , "--info" , "--health" , "--attributes" , "--tolerance=verypermissive" , "--nocheck=standby" , "--format=brief" , "--log=error" , "--device=" + device .Type , device .Name ).Output ()
68
83
if err != nil {
@@ -72,7 +87,7 @@ func readSMARTctl(logger log.Logger, device Device) (gjson.Result, bool) {
72
87
rcOk := resultCodeIsOk (logger , device , json .Get ("smartctl.exit_status" ).Int ())
73
88
jsonOk := jsonIsOk (logger , json )
74
89
level .Debug (logger ).Log ("msg" , "Collected S.M.A.R.T. json data" , "device" , device .Info_Name , "duration" , time .Since (start ))
75
- return json , rcOk && jsonOk
90
+ results <- SMARTresult { device , json , rcOk && jsonOk }
76
91
}
77
92
78
93
func readSMARTctlDevices (logger log.Logger ) gjson.Result {
@@ -89,23 +104,43 @@ func readSMARTctlDevices(logger log.Logger) gjson.Result {
89
104
return parseJSON (string (out ))
90
105
}
91
106
107
+ // Refresh all devices' json
108
+ func refreshAllDevices (logger log.Logger , devices []Device ) {
109
+ if * smartctlFakeData {
110
+ return
111
+ }
112
+
113
+ pool := createPool ()
114
+ for _ , device := range devices {
115
+ refreshData (logger , device , & pool )
116
+ }
117
+ for pool .expected > 0 {
118
+ result := <- pool .results
119
+ if result .ok {
120
+ jsonCache .Store (result .device , JSONCache {JSON : result .JSON , LastCollect : time .Now ()})
121
+ }
122
+ pool .expected --
123
+ }
124
+ close (pool .results )
125
+ }
126
+
92
127
// Select json source and parse
128
+ func refreshData (logger log.Logger , device Device , pool * SMARTctlWorkerPool ) {
129
+ cacheValue , cacheOk := jsonCache .Load (device )
130
+ if ! cacheOk || time .Now ().After (cacheValue .(JSONCache ).LastCollect .Add (* smartctlInterval )) {
131
+ go readSMARTctl (logger , device , pool .results )
132
+ pool .expected ++
133
+ }
134
+ }
135
+
93
136
func readData (logger log.Logger , device Device ) gjson.Result {
94
137
if * smartctlFakeData {
95
138
return readFakeSMARTctl (logger , device )
96
139
}
97
140
98
- cacheValue , cacheOk := jsonCache .Load (device )
99
- if ! cacheOk || time .Now ().After (cacheValue .(JSONCache ).LastCollect .Add (* smartctlInterval )) {
100
- json , ok := readSMARTctl (logger , device )
101
- if ok {
102
- jsonCache .Store (device , JSONCache {JSON : json , LastCollect : time .Now ()})
103
- j , found := jsonCache .Load (device )
104
- if ! found {
105
- level .Warn (logger ).Log ("msg" , "device not found" , "device" , device .Info_Name )
106
- }
107
- return j .(JSONCache ).JSON
108
- }
141
+ cacheValue , found := jsonCache .Load (device )
142
+ if ! found {
143
+ level .Warn (logger ).Log ("msg" , "device not found" , "device" , device .Info_Name )
109
144
return gjson.Result {}
110
145
}
111
146
return cacheValue .(JSONCache ).JSON
0 commit comments