-
Notifications
You must be signed in to change notification settings - Fork 13
/
filestat.go
150 lines (129 loc) · 3.27 KB
/
filestat.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package filestat
import (
"context"
"crypto/sha256"
"fmt"
"io"
"os"
"github.com/circonus-labs/circonus-unified-agent/cua"
"github.com/circonus-labs/circonus-unified-agent/internal/globpath"
"github.com/circonus-labs/circonus-unified-agent/plugins/inputs"
)
const sampleConfig = `
## Files to gather stats about.
## These accept standard unix glob matching rules, but with the addition of
## ** as a "super asterisk". ie:
## "/var/log/**.log" -> recursively find all .log files in /var/log
## "/var/log/*/*.log" -> find all .log files with a parent dir in /var/log
## "/var/log/apache.log" -> just tail the apache log file
##
## See https://github.com/gobwas/glob for more examples
##
files = ["/var/log/**.log"]
## If true, read the entire file and calculate an sha256 checksum.
sha256 = false
`
type FileStat struct {
Log cua.Logger
globs map[string]*globpath.GlobPath // maps full file paths to globmatch obj
Files []string
SHA256 bool
}
func NewFileStat() *FileStat {
return &FileStat{
globs: make(map[string]*globpath.GlobPath),
}
}
func (*FileStat) Description() string {
return "Read stats about given file(s)"
}
func (*FileStat) SampleConfig() string { return sampleConfig }
func (f *FileStat) Gather(ctx context.Context, acc cua.Accumulator) error {
var err error
for _, filepath := range f.Files {
// Get the compiled glob object for this filepath
g, ok := f.globs[filepath]
if !ok {
if g, err = globpath.Compile(filepath); err != nil {
acc.AddError(err)
continue
}
f.globs[filepath] = g
}
files := g.Match()
if len(files) == 0 {
acc.AddFields("filestat",
map[string]interface{}{
"exists": int64(0),
},
map[string]string{
"file": filepath,
})
continue
}
for _, fileName := range files {
tags := map[string]string{
"file": fileName,
}
fields := map[string]interface{}{
"exists": int64(1),
}
fileInfo, err := os.Stat(fileName)
if os.IsNotExist(err) {
fields["exists"] = int64(0)
}
if fileInfo == nil {
f.Log.Errorf("Unable to get info for file %q, possible permissions issue",
fileName)
} else {
fields["size_bytes"] = fileInfo.Size()
fields["modification_time"] = fileInfo.ModTime().UnixNano()
}
if f.SHA256 {
sig, err := getSHA256(fileName)
if err != nil {
acc.AddError(err)
} else {
fields["sha256_sum"] = sig
}
}
acc.AddFields("filestat", fields, tags)
}
}
return nil
}
// // Read given file and calculate an md5 hash.
// func getMd5(file string) (string, error) {
// of, err := os.Open(file)
// if err != nil {
// return "", err
// }
// defer of.Close()
// hash := md5.New()
// _, err = io.Copy(hash, of)
// if err != nil {
// // fatal error
// return "", err
// }
// return fmt.Sprintf("%x", hash.Sum(nil)), nil
// }
// Read given file and calculate an sha256 hash.
func getSHA256(file string) (string, error) {
of, err := os.Open(file)
if err != nil {
return "", fmt.Errorf("open: %w", err)
}
defer of.Close()
hash := sha256.New()
_, err = io.Copy(hash, of)
if err != nil {
// fatal error
return "", fmt.Errorf("copy: %w", err)
}
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}
func init() {
inputs.Add("filestat", func() cua.Input {
return NewFileStat()
})
}