github.com/netdata/go.d.plugin@v0.58.1/modules/filecheck/collect_dirs.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package filecheck 4 5 import ( 6 "fmt" 7 "os" 8 "path/filepath" 9 "strings" 10 "time" 11 12 "github.com/netdata/go.d.plugin/agent/module" 13 ) 14 15 func (fc *Filecheck) collectDirs(ms map[string]int64) { 16 curTime := time.Now() 17 if time.Since(fc.lastDiscoveryDirs) >= fc.DiscoveryEvery.Duration { 18 fc.lastDiscoveryDirs = curTime 19 fc.curDirs = fc.discoveryDirs() 20 fc.updateDirsCharts(fc.curDirs) 21 } 22 23 for _, path := range fc.curDirs { 24 fc.collectDir(ms, path, curTime) 25 } 26 ms["num_of_dirs"] = int64(len(fc.curDirs)) 27 } 28 29 func (fc *Filecheck) collectDir(ms map[string]int64, path string, curTime time.Time) { 30 info, err := os.Stat(path) 31 if err != nil { 32 if os.IsNotExist(err) { 33 ms[dirDimID(path, "exists")] = 0 34 } else { 35 ms[dirDimID(path, "exists")] = 1 36 } 37 fc.Debug(err) 38 return 39 } 40 41 if !info.IsDir() { 42 return 43 } 44 45 ms[dirDimID(path, "exists")] = 1 46 ms[dirDimID(path, "mtime_ago")] = int64(curTime.Sub(info.ModTime()).Seconds()) 47 if num, err := calcDirNumOfFiles(path); err == nil { 48 ms[dirDimID(path, "num_of_files")] = int64(num) 49 } 50 if fc.Dirs.CollectDirSize { 51 if size, err := calcDirSize(path); err == nil { 52 ms[dirDimID(path, "size_bytes")] = size 53 } 54 } 55 } 56 57 func (fc Filecheck) discoveryDirs() (dirs []string) { 58 for _, path := range fc.Dirs.Include { 59 if hasMeta(path) { 60 continue 61 } 62 dirs = append(dirs, path) 63 } 64 65 for _, path := range fc.Dirs.Include { 66 if !hasMeta(path) { 67 continue 68 } 69 matches, _ := filepath.Glob(path) 70 for _, v := range matches { 71 fi, err := os.Lstat(v) 72 if err == nil && fi.IsDir() { 73 dirs = append(dirs, v) 74 } 75 } 76 } 77 return removeDuplicates(dirs) 78 } 79 80 func (fc *Filecheck) updateDirsCharts(dirs []string) { 81 set := make(map[string]bool, len(dirs)) 82 for _, path := range dirs { 83 set[path] = true 84 if !fc.collectedDirs[path] { 85 fc.collectedDirs[path] = true 86 fc.addDirToCharts(path) 87 } 88 } 89 for path := range fc.collectedDirs { 90 if !set[path] { 91 delete(fc.collectedDirs, path) 92 fc.removeDirFromCharts(path) 93 } 94 } 95 } 96 97 func (fc *Filecheck) addDirToCharts(path string) { 98 for _, chart := range *fc.Charts() { 99 if !strings.HasPrefix(chart.ID, "dir_") { 100 continue 101 } 102 103 var id string 104 switch chart.ID { 105 case dirExistenceChart.ID: 106 id = dirDimID(path, "exists") 107 case dirModTimeChart.ID: 108 id = dirDimID(path, "mtime_ago") 109 case dirNumOfFilesChart.ID: 110 id = dirDimID(path, "num_of_files") 111 case dirSizeChart.ID: 112 id = dirDimID(path, "size_bytes") 113 default: 114 fc.Warningf("add dimension: couldn't dim id for '%s' chart (dir '%s')", chart.ID, path) 115 continue 116 } 117 118 dim := &module.Dim{ID: id, Name: reSpace.ReplaceAllString(path, "_")} 119 120 if err := chart.AddDim(dim); err != nil { 121 fc.Warning(err) 122 continue 123 } 124 chart.MarkNotCreated() 125 } 126 } 127 128 func (fc *Filecheck) removeDirFromCharts(path string) { 129 for _, chart := range *fc.Charts() { 130 if !strings.HasPrefix(chart.ID, "dir_") { 131 continue 132 } 133 134 var id string 135 switch chart.ID { 136 case dirExistenceChart.ID: 137 id = dirDimID(path, "exists") 138 case dirModTimeChart.ID: 139 id = dirDimID(path, "mtime_ago") 140 case dirNumOfFilesChart.ID: 141 id = dirDimID(path, "num_of_files") 142 case dirSizeChart.ID: 143 id = dirDimID(path, "size_bytes") 144 default: 145 fc.Warningf("remove dimension: couldn't dim id for '%s' chart (dir '%s')", chart.ID, path) 146 continue 147 } 148 149 if err := chart.MarkDimRemove(id, true); err != nil { 150 fc.Warning(err) 151 continue 152 } 153 chart.MarkNotCreated() 154 } 155 } 156 157 func dirDimID(path, metric string) string { 158 return fmt.Sprintf("dir_%s_%s", reSpace.ReplaceAllString(path, "_"), metric) 159 } 160 161 func calcDirNumOfFiles(dirpath string) (int, error) { 162 f, err := os.Open(dirpath) 163 if err != nil { 164 return 0, err 165 } 166 defer func() { _ = f.Close() }() 167 // TODO: include dirs? 168 names, err := f.Readdirnames(-1) 169 return len(names), err 170 } 171 172 func calcDirSize(dirpath string) (int64, error) { 173 var size int64 174 err := filepath.Walk(dirpath, func(_ string, info os.FileInfo, err error) error { 175 if err != nil { 176 return err 177 } 178 if !info.IsDir() { 179 size += info.Size() 180 } 181 return nil 182 }) 183 return size, err 184 }