Tail input plugin
This commit is contained in:
parent
411d8d7439
commit
b9c24189e4
1
Godeps
1
Godeps
|
@ -23,6 +23,7 @@ github.com/gonuts/go-shellquote e842a11b24c6abfb3dd27af69a17f482e4b483c2
|
||||||
github.com/gorilla/context 1ea25387ff6f684839d82767c1733ff4d4d15d0a
|
github.com/gorilla/context 1ea25387ff6f684839d82767c1733ff4d4d15d0a
|
||||||
github.com/gorilla/mux c9e326e2bdec29039a3761c07bece13133863e1e
|
github.com/gorilla/mux c9e326e2bdec29039a3761c07bece13133863e1e
|
||||||
github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478
|
github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478
|
||||||
|
github.com/hpcloud/tail b2940955ab8b26e19d43a43c4da0475dd81bdb56
|
||||||
github.com/influxdata/config b79f6829346b8d6e78ba73544b1e1038f1f1c9da
|
github.com/influxdata/config b79f6829346b8d6e78ba73544b1e1038f1f1c9da
|
||||||
github.com/influxdata/influxdb 21db76b3374c733f37ed16ad93f3484020034351
|
github.com/influxdata/influxdb 21db76b3374c733f37ed16ad93f3484020034351
|
||||||
github.com/influxdata/toml af4df43894b16e3fd2b788d01bd27ad0776ef2d0
|
github.com/influxdata/toml af4df43894b16e3fd2b788d01bd27ad0776ef2d0
|
||||||
|
|
|
@ -56,6 +56,7 @@ import (
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/statsd"
|
_ "github.com/influxdata/telegraf/plugins/inputs/statsd"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/sysstat"
|
_ "github.com/influxdata/telegraf/plugins/inputs/sysstat"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/system"
|
_ "github.com/influxdata/telegraf/plugins/inputs/system"
|
||||||
|
_ "github.com/influxdata/telegraf/plugins/inputs/tail"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/tcp_listener"
|
_ "github.com/influxdata/telegraf/plugins/inputs/tcp_listener"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/trig"
|
_ "github.com/influxdata/telegraf/plugins/inputs/trig"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/twemproxy"
|
_ "github.com/influxdata/telegraf/plugins/inputs/twemproxy"
|
||||||
|
|
|
@ -14,8 +14,14 @@ import (
|
||||||
const sampleConfig = `
|
const sampleConfig = `
|
||||||
## Files to gather stats about.
|
## Files to gather stats about.
|
||||||
## These accept standard unix glob matching rules, but with the addition of
|
## These accept standard unix glob matching rules, but with the addition of
|
||||||
## ** as a "super asterisk". See https://github.com/gobwas/glob.
|
## ** as a "super asterisk". ie:
|
||||||
files = ["/etc/telegraf/telegraf.conf", "/var/log/**.log"]
|
## "/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 md5 checksum.
|
## If true, read the entire file and calculate an md5 checksum.
|
||||||
md5 = false
|
md5 = false
|
||||||
`
|
`
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# tail Input Plugin
|
||||||
|
|
||||||
|
The tail plugin "tails" a logfile and parses each log message.
|
||||||
|
|
||||||
|
By default, the tail plugin acts like the following unix tail command:
|
||||||
|
|
||||||
|
```
|
||||||
|
tail --follow=name --lines=0 --retry myfile.log
|
||||||
|
```
|
||||||
|
|
||||||
|
- `--follow=name` means that it will follow the _name_ of the given file, so
|
||||||
|
that it will be compatible with log-rotated files.
|
||||||
|
- `--lines=0` means that it will start at the end of the file (unless
|
||||||
|
the `from_beginning` option is set).
|
||||||
|
- `--retry` means it will retry on inaccessible files.
|
||||||
|
|
||||||
|
see http://man7.org/linux/man-pages/man1/tail.1.html for more details.
|
||||||
|
|
||||||
|
The plugin expects messages in one of the
|
||||||
|
[Telegraf Input Data Formats](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md).
|
||||||
|
|
||||||
|
### Configuration:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Stream a log file, like the tail -f command
|
||||||
|
[[inputs.tail]]
|
||||||
|
# SampleConfig
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
package tail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/hpcloud/tail"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf"
|
||||||
|
"github.com/influxdata/telegraf/internal/globpath"
|
||||||
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||||||
|
"github.com/influxdata/telegraf/plugins/parsers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tail struct {
|
||||||
|
Files []string
|
||||||
|
FromBeginning bool
|
||||||
|
|
||||||
|
tailers []*tail.Tail
|
||||||
|
parser parsers.Parser
|
||||||
|
wg sync.WaitGroup
|
||||||
|
acc telegraf.Accumulator
|
||||||
|
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
const sampleConfig = `
|
||||||
|
## files to tail.
|
||||||
|
## 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/mymetrics.out"]
|
||||||
|
## Read file from beginning.
|
||||||
|
from_beginning = false
|
||||||
|
|
||||||
|
## Data format to consume.
|
||||||
|
## Each data format has it's 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"
|
||||||
|
`
|
||||||
|
|
||||||
|
func (t *Tail) SampleConfig() string {
|
||||||
|
return sampleConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tail) Description() string {
|
||||||
|
return "Stream a log file, like the tail -f command"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tail) Gather(acc telegraf.Accumulator) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tail) Start(acc telegraf.Accumulator) error {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
t.acc = acc
|
||||||
|
|
||||||
|
var seek tail.SeekInfo
|
||||||
|
if !t.FromBeginning {
|
||||||
|
seek.Whence = 2
|
||||||
|
seek.Offset = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var errS string
|
||||||
|
// Create a "tailer" for each file
|
||||||
|
for _, filepath := range t.Files {
|
||||||
|
g, err := globpath.Compile(filepath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR Glob %s failed to compile, %s", filepath, err)
|
||||||
|
}
|
||||||
|
for file, _ := range g.Match() {
|
||||||
|
tailer, err := tail.TailFile(file,
|
||||||
|
tail.Config{
|
||||||
|
ReOpen: true,
|
||||||
|
Follow: true,
|
||||||
|
Location: &seek,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
errS += err.Error() + " "
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// create a goroutine for each "tailer"
|
||||||
|
go t.receiver(tailer)
|
||||||
|
t.tailers = append(t.tailers, tailer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errS != "" {
|
||||||
|
return fmt.Errorf(errS)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is launched as a goroutine to continuously watch a tailed logfile
|
||||||
|
// for changes, parse any incoming msgs, and add to the accumulator.
|
||||||
|
func (t *Tail) receiver(tailer *tail.Tail) {
|
||||||
|
t.wg.Add(1)
|
||||||
|
defer t.wg.Done()
|
||||||
|
|
||||||
|
var m telegraf.Metric
|
||||||
|
var err error
|
||||||
|
var line *tail.Line
|
||||||
|
for line = range tailer.Lines {
|
||||||
|
if line.Err != nil {
|
||||||
|
log.Printf("ERROR tailing file %s, Error: %s\n",
|
||||||
|
tailer.Filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m, err = t.parser.ParseLine(line.Text)
|
||||||
|
if err == nil {
|
||||||
|
t.acc.AddFields(m.Name(), m.Fields(), m.Tags(), m.Time())
|
||||||
|
} else {
|
||||||
|
log.Printf("Malformed log line in %s: [%s], Error: %s\n",
|
||||||
|
tailer.Filename, line.Text, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tail) Stop() {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
for _, t := range t.tailers {
|
||||||
|
err := t.Stop()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR stopping tail on file %s\n", t.Filename)
|
||||||
|
}
|
||||||
|
t.Cleanup()
|
||||||
|
}
|
||||||
|
t.wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tail) SetParser(parser parsers.Parser) {
|
||||||
|
t.parser = parser
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
inputs.Add("tail", func() telegraf.Input {
|
||||||
|
return &Tail{
|
||||||
|
FromBeginning: false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package tail
|
|
@ -221,7 +221,10 @@ func (t *TcpListener) handler(conn *net.TCPConn, id string) {
|
||||||
// tcpParser parses the incoming tcp byte packets
|
// tcpParser parses the incoming tcp byte packets
|
||||||
func (t *TcpListener) tcpParser() error {
|
func (t *TcpListener) tcpParser() error {
|
||||||
defer t.wg.Done()
|
defer t.wg.Done()
|
||||||
|
|
||||||
var packet []byte
|
var packet []byte
|
||||||
|
var metrics []telegraf.Metric
|
||||||
|
var err error
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.done:
|
case <-t.done:
|
||||||
|
@ -230,7 +233,7 @@ func (t *TcpListener) tcpParser() error {
|
||||||
if len(packet) == 0 {
|
if len(packet) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
metrics, err := t.parser.Parse(packet)
|
metrics, err = t.parser.Parse(packet)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.storeMetrics(metrics)
|
t.storeMetrics(metrics)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -135,12 +135,14 @@ func (u *UdpListener) udpParser() error {
|
||||||
defer u.wg.Done()
|
defer u.wg.Done()
|
||||||
|
|
||||||
var packet []byte
|
var packet []byte
|
||||||
|
var metrics []telegraf.Metric
|
||||||
|
var err error
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-u.done:
|
case <-u.done:
|
||||||
return nil
|
return nil
|
||||||
case packet = <-u.in:
|
case packet = <-u.in:
|
||||||
metrics, err := u.parser.Parse(packet)
|
metrics, err = u.parser.Parse(packet)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
u.storeMetrics(metrics)
|
u.storeMetrics(metrics)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue