master
go 266 lines 6.5 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package filecheck
4
5 import (
6 "fmt"
7 "strings"
8
9 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
10 )
11
12 const (
13 prioFileExistenceStatus = collectorapi.Priority + iota
14 prioFileModificationTimeAgo
15 prioFileSize
16
17 prioDirExistenceStatus
18 prioDirModificationTimeAgo
19 prioDirSize
20 prioDirFilesCount
21 )
22
23 var (
24 fileExistenceStatusChartTmpl = collectorapi.Chart{
25 ID: "file_%s_existence_status",
26 Title: "File existence",
27 Units: "status",
28 Fam: "file existence",
29 Ctx: "filecheck.file_existence_status",
30 Priority: prioFileExistenceStatus,
31 Dims: collectorapi.Dims{
32 {ID: "file_%s_existence_status_exist", Name: "exist"},
33 {ID: "file_%s_existence_status_not_exist", Name: "not_exist"},
34 },
35 }
36
37 fileModificationTimeAgoChartTmpl = collectorapi.Chart{
38 ID: "file_%s_modification_time_ago",
39 Title: "File time since the last modification",
40 Units: "seconds",
41 Fam: "file mtime",
42 Ctx: "filecheck.file_modification_time_ago",
43 Priority: prioFileModificationTimeAgo,
44 Dims: collectorapi.Dims{
45 {ID: "file_%s_mtime_ago", Name: "mtime_ago"},
46 },
47 }
48 fileSizeChartTmpl = collectorapi.Chart{
49 ID: "file_%s_size",
50 Title: "File size",
51 Units: "bytes",
52 Fam: "file size",
53 Ctx: "filecheck.file_size_bytes",
54 Priority: prioFileSize,
55 Dims: collectorapi.Dims{
56 {ID: "file_%s_size_bytes", Name: "size"},
57 },
58 }
59 )
60
61 var (
62 dirExistenceStatusChartTmpl = collectorapi.Chart{
63 ID: "dir_%s_existence_status",
64 Title: "Directory existence",
65 Units: "status",
66 Fam: "dir existence",
67 Ctx: "filecheck.dir_existence_status",
68 Priority: prioDirExistenceStatus,
69 Dims: collectorapi.Dims{
70 {ID: "dir_%s_existence_status_exist", Name: "exist"},
71 {ID: "dir_%s_existence_status_not_exist", Name: "not_exist"},
72 },
73 }
74
75 dirModificationTimeAgoChartTmpl = collectorapi.Chart{
76 ID: "dir_%s_modification_time_ago",
77 Title: "Directory time since the last modification",
78 Units: "seconds",
79 Fam: "dir mtime",
80 Ctx: "filecheck.dir_modification_time_ago",
81 Priority: prioDirModificationTimeAgo,
82 Dims: collectorapi.Dims{
83 {ID: "dir_%s_mtime_ago", Name: "mtime_ago"},
84 },
85 }
86 dirSizeChartTmpl = collectorapi.Chart{
87 ID: "dir_%s_size",
88 Title: "Directory size",
89 Units: "bytes",
90 Fam: "dir size",
91 Ctx: "filecheck.dir_size_bytes",
92 Priority: prioDirSize,
93 Dims: collectorapi.Dims{
94 {ID: "dir_%s_size_bytes", Name: "size"},
95 },
96 }
97 dirFilesCountChartTmpl = collectorapi.Chart{
98 ID: "dir_%s_files_count",
99 Title: "Directory files count",
100 Units: "files",
101 Fam: "dir files",
102 Ctx: "filecheck.dir_files_count",
103 Priority: prioDirFilesCount,
104 Dims: collectorapi.Dims{
105 {ID: "dir_%s_files_count", Name: "files"},
106 },
107 }
108 )
109
110 func (c *Collector) updateFileCharts(infos []*statInfo) {
111 seen := make(map[string]bool)
112
113 for _, info := range infos {
114 seen[info.path] = true
115
116 sf := c.seenFiles.getp(info.path)
117
118 if !sf.hasExistenceCharts {
119 sf.hasExistenceCharts = true
120 c.addFileCharts(info.path,
121 fileExistenceStatusChartTmpl.Copy(),
122 )
123 }
124
125 if !sf.hasOtherCharts && info.fi != nil {
126 sf.hasOtherCharts = true
127 c.addFileCharts(info.path,
128 fileModificationTimeAgoChartTmpl.Copy(),
129 fileSizeChartTmpl.Copy(),
130 )
131
132 } else if sf.hasOtherCharts && info.fi == nil {
133 sf.hasOtherCharts = false
134 c.removeFileOtherCharts(info.path)
135 }
136 }
137
138 for path := range c.seenFiles.items {
139 if !seen[path] {
140 delete(c.seenFiles.items, path)
141 c.removeFileAllCharts(path)
142 }
143 }
144 }
145
146 func (c *Collector) updateDirCharts(infos []*statInfo) {
147 seen := make(map[string]bool)
148
149 for _, info := range infos {
150 seen[info.path] = true
151
152 sd := c.seenDirs.getp(info.path)
153
154 if !sd.hasExistenceCharts {
155 sd.hasExistenceCharts = true
156 c.addDirCharts(info.path,
157 dirExistenceStatusChartTmpl.Copy(),
158 )
159 }
160
161 if !sd.hasOtherCharts && info.fi != nil {
162 sd.hasOtherCharts = true
163 c.addDirCharts(info.path,
164 dirModificationTimeAgoChartTmpl.Copy(),
165 dirFilesCountChartTmpl.Copy(),
166 )
167 if c.Dirs.CollectDirSize {
168 c.addDirCharts(info.path,
169 dirSizeChartTmpl.Copy(),
170 )
171 }
172
173 } else if sd.hasOtherCharts && info.fi == nil {
174 sd.hasOtherCharts = false
175 c.removeDirOtherCharts(info.path)
176 }
177 }
178
179 for path := range c.seenDirs.items {
180 if !seen[path] {
181 delete(c.seenDirs.items, path)
182 c.removeDirAllCharts(path)
183 }
184 }
185 }
186
187 func (c *Collector) addFileCharts(filePath string, chartsTmpl ...*collectorapi.Chart) {
188 cs := append(collectorapi.Charts{}, chartsTmpl...)
189 charts := cs.Copy()
190
191 for _, chart := range *charts {
192 chart.ID = fmt.Sprintf(chart.ID, cleanPath(filePath))
193 chart.Labels = []collectorapi.Label{
194 {Key: "file_path", Value: filePath},
195 }
196 for _, dim := range chart.Dims {
197 dim.ID = fmt.Sprintf(dim.ID, filePath)
198 }
199 }
200
201 if err := c.Charts().Add(*charts...); err != nil {
202 c.Warning(err)
203 }
204 }
205
206 func (c *Collector) addDirCharts(dirPath string, chartsTmpl ...*collectorapi.Chart) {
207 cs := append(collectorapi.Charts{}, chartsTmpl...)
208 charts := cs.Copy()
209
210 for _, chart := range *charts {
211 chart.ID = fmt.Sprintf(chart.ID, cleanPath(dirPath))
212 chart.Labels = []collectorapi.Label{
213 {Key: "dir_path", Value: dirPath},
214 }
215 for _, dim := range chart.Dims {
216 dim.ID = fmt.Sprintf(dim.ID, dirPath)
217 }
218 }
219
220 if err := c.Charts().Add(*charts...); err != nil {
221 c.Warning(err)
222 }
223 }
224
225 func (c *Collector) removeFileAllCharts(filePath string) {
226 px := fmt.Sprintf("file_%s_", cleanPath(filePath))
227 c.removeCharts(func(id string) bool {
228 return strings.HasPrefix(id, px)
229 })
230 }
231
232 func (c *Collector) removeFileOtherCharts(filePath string) {
233 px := fmt.Sprintf("file_%s_", cleanPath(filePath))
234 c.removeCharts(func(id string) bool {
235 return strings.HasPrefix(id, px) && !strings.HasSuffix(id, "existence_status")
236 })
237 }
238
239 func (c *Collector) removeDirAllCharts(dirPath string) {
240 px := fmt.Sprintf("dir_%s_", cleanPath(dirPath))
241 c.removeCharts(func(id string) bool {
242 return strings.HasPrefix(id, px)
243 })
244 }
245
246 func (c *Collector) removeDirOtherCharts(dirPath string) {
247 px := fmt.Sprintf("dir_%s_", cleanPath(dirPath))
248 c.removeCharts(func(id string) bool {
249 return strings.HasPrefix(id, px) && !strings.HasSuffix(id, "existence_status")
250 })
251 }
252
253 func (c *Collector) removeCharts(match func(id string) bool) {
254 for _, chart := range *c.Charts() {
255 if match(chart.ID) {
256 chart.MarkRemove()
257 chart.MarkNotCreated()
258 }
259 }
260 }
261
262 func cleanPath(path string) string {
263 path = strings.ReplaceAll(path, " ", "_")
264 path = strings.ReplaceAll(path, ".", "_")
265 return path
266 }