forked from kumina/postfix_exporter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
logsource_file.go
94 lines (82 loc) · 2.55 KB
/
logsource_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
package main
import (
"context"
"io"
"log"
"github.com/alecthomas/kingpin/v2"
"github.com/nxadm/tail"
)
var defaultConfig = tail.Config{
ReOpen: true, // reopen the file if it's rotated
MustExist: true, // fail immediately if the file is missing or has incorrect permissions
Follow: true, // run in follow mode
Location: &tail.SeekInfo{Whence: io.SeekEnd}, // seek to end of file
Logger: tail.DiscardingLogger,
}
// A FileLogSource can read lines from a file.
type FileLogSource struct {
tailer *tail.Tail
}
// NewFileLogSource creates a new log source, tailing the given file.
func NewFileLogSource(path string, config tail.Config) (*FileLogSource, error) {
tailer, err := tail.TailFile(path, config)
if err != nil {
return nil, err
}
return &FileLogSource{tailer}, nil
}
func (s *FileLogSource) Close() error {
defer s.tailer.Cleanup()
go func() {
// Stop() waits for the tailer goroutine to shut down, but it
// can be blocking on sending on the Lines channel...
for range s.tailer.Lines {
}
}()
return s.tailer.Stop()
}
func (s *FileLogSource) Path() string {
return s.tailer.Filename
}
func (s *FileLogSource) Read(ctx context.Context) (string, error) {
select {
case line, ok := <-s.tailer.Lines:
if !ok {
return "", io.EOF
}
return line.Text, nil
case <-ctx.Done():
return "", ctx.Err()
}
}
// A fileLogSourceFactory is a factory than can create log sources
// from command line flags.
//
// Because this factory is enabled by default, it must always be
// registered last.
type fileLogSourceFactory struct {
path string
mustExist bool
debug bool
}
func (f *fileLogSourceFactory) Init(app *kingpin.Application) {
app.Flag("postfix.logfile_path", "Path where Postfix writes log entries.").Default("/var/log/mail.log").StringVar(&f.path)
app.Flag("postfix.logfile_must_exist", "Fail if the log file doesn't exist.").Default("true").BoolVar(&f.mustExist)
app.Flag("postfix.logfile_debug", "Enable debug logging for the log file.").Default("false").BoolVar(&f.debug)
}
// config returns a tail.Config configured from the factory's fields.
func (f fileLogSourceFactory) config() tail.Config {
conf := defaultConfig
conf.MustExist = f.mustExist
if f.debug {
conf.Logger = tail.DefaultLogger
}
return conf
}
func (f *fileLogSourceFactory) New(ctx context.Context) (LogSourceCloser, error) {
if f.path == "" {
return nil, nil
}
log.Printf("Reading log events from %s", f.path)
return NewFileLogSource(f.path, f.config())
}