2016-04-21 01:51:25 +00:00
|
|
|
package filestat
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/md5"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/influxdata/telegraf"
|
2016-04-23 17:42:28 +00:00
|
|
|
"github.com/influxdata/telegraf/internal/globpath"
|
2016-04-21 01:51:25 +00:00
|
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
|
|
|
)
|
|
|
|
|
|
|
|
const sampleConfig = `
|
|
|
|
## Files to gather stats about.
|
|
|
|
## These accept standard unix glob matching rules, but with the addition of
|
2016-04-22 21:47:26 +00:00
|
|
|
## ** 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"]
|
2016-04-21 01:51:25 +00:00
|
|
|
## If true, read the entire file and calculate an md5 checksum.
|
|
|
|
md5 = false
|
|
|
|
`
|
|
|
|
|
|
|
|
type FileStat struct {
|
|
|
|
Md5 bool
|
|
|
|
Files []string
|
|
|
|
|
2016-04-23 17:42:28 +00:00
|
|
|
// maps full file paths to globmatch obj
|
|
|
|
globs map[string]*globpath.GlobPath
|
2016-04-21 01:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewFileStat() *FileStat {
|
|
|
|
return &FileStat{
|
2016-04-23 17:42:28 +00:00
|
|
|
globs: make(map[string]*globpath.GlobPath),
|
2016-04-21 01:51:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (_ *FileStat) Description() string {
|
|
|
|
return "Read stats about given file(s)"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (_ *FileStat) SampleConfig() string { return sampleConfig }
|
|
|
|
|
|
|
|
func (f *FileStat) Gather(acc telegraf.Accumulator) error {
|
|
|
|
var errS string
|
|
|
|
var err error
|
|
|
|
|
|
|
|
for _, filepath := range f.Files {
|
|
|
|
// Get the compiled glob object for this filepath
|
|
|
|
g, ok := f.globs[filepath]
|
|
|
|
if !ok {
|
2016-04-23 17:42:28 +00:00
|
|
|
if g, err = globpath.Compile(filepath); err != nil {
|
2016-04-21 01:51:25 +00:00
|
|
|
errS += err.Error() + " "
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
f.globs[filepath] = g
|
|
|
|
}
|
|
|
|
|
2016-04-24 20:37:44 +00:00
|
|
|
files := g.Match()
|
|
|
|
if len(files) == 0 {
|
|
|
|
acc.AddFields("filestat",
|
|
|
|
map[string]interface{}{
|
|
|
|
"exists": int64(0),
|
|
|
|
},
|
|
|
|
map[string]string{
|
|
|
|
"file": filepath,
|
|
|
|
})
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for fileName, fileInfo := range files {
|
2016-04-21 01:51:25 +00:00
|
|
|
tags := map[string]string{
|
2016-04-24 20:37:44 +00:00
|
|
|
"file": fileName,
|
2016-04-21 01:51:25 +00:00
|
|
|
}
|
|
|
|
fields := map[string]interface{}{
|
2016-04-24 20:37:44 +00:00
|
|
|
"exists": int64(1),
|
|
|
|
"size_bytes": fileInfo.Size(),
|
2016-04-21 01:51:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if f.Md5 {
|
2016-04-24 20:37:44 +00:00
|
|
|
md5, err := getMd5(fileName)
|
2016-04-21 01:51:25 +00:00
|
|
|
if err != nil {
|
|
|
|
errS += err.Error() + " "
|
|
|
|
} else {
|
|
|
|
fields["md5_sum"] = md5
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
acc.AddFields("filestat", fields, tags)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if errS != "" {
|
|
|
|
return fmt.Errorf(errS)
|
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
inputs.Add("filestat", func() telegraf.Input {
|
|
|
|
return NewFileStat()
|
|
|
|
})
|
|
|
|
}
|