forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
file.go
129 lines (110 loc) · 3.13 KB
/
file.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
package file
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/dimchansky/utfbom"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal/globpath"
"github.com/influxdata/telegraf/plugins/common/encoding"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/influxdata/telegraf/plugins/parsers"
)
type File struct {
Files []string `toml:"files"`
FileTag string `toml:"file_tag"`
CharacterEncoding string `toml:"character_encoding"`
parser parsers.Parser
filenames []string
decoder *encoding.Decoder
}
const sampleConfig = `
## Files to parse each interval. Accept standard unix glob matching rules,
## as well as ** to match recursive files and directories.
files = ["/tmp/metrics.out"]
## Name a tag containing the name of the file the data was parsed from. Leave empty
## to disable.
# file_tag = ""
## Character encoding to use when interpreting the file contents. Invalid
## characters are replaced using the unicode replacement character. When set
## to the empty string the data is not decoded to text.
## ex: character_encoding = "utf-8"
## character_encoding = "utf-16le"
## character_encoding = "utf-16be"
## character_encoding = ""
# character_encoding = ""
## The dataformat to be read from files
## Each data format has its own unique set of configuration options, read
## more about them here:
## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
data_format = "influx"
`
// SampleConfig returns the default configuration of the Input
func (f *File) SampleConfig() string {
return sampleConfig
}
func (f *File) Description() string {
return "Parse a complete file each interval"
}
func (f *File) Init() error {
var err error
f.decoder, err = encoding.NewDecoder(f.CharacterEncoding)
return err
}
func (f *File) Gather(acc telegraf.Accumulator) error {
err := f.refreshFilePaths()
if err != nil {
return err
}
for _, k := range f.filenames {
metrics, err := f.readMetric(k)
if err != nil {
return err
}
for _, m := range metrics {
if f.FileTag != "" {
m.AddTag(f.FileTag, filepath.Base(k))
}
acc.AddMetric(m)
}
}
return nil
}
func (f *File) SetParser(p parsers.Parser) {
f.parser = p
}
func (f *File) refreshFilePaths() error {
var allFiles []string
for _, file := range f.Files {
g, err := globpath.Compile(file)
if err != nil {
return fmt.Errorf("could not compile glob %v: %v", file, err)
}
files := g.Match()
if len(files) <= 0 {
return fmt.Errorf("could not find file: %v", file)
}
allFiles = append(allFiles, files...)
}
f.filenames = allFiles
return nil
}
func (f *File) readMetric(filename string) ([]telegraf.Metric, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
r, _ := utfbom.Skip(f.decoder.Reader(file))
fileContents, err := ioutil.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("E! Error file: %v could not be read, %s", filename, err)
}
return f.parser.Parse(fileContents)
}
func init() {
inputs.Add("file", func() telegraf.Input {
return &File{}
})
}