|
@@ -89,12 +89,25 @@ type LogFile struct {
|
|
|
filesRefCounter refCounter // keep reference-counted of decompressed files
|
|
|
notifyRotate *pubsub.Publisher
|
|
|
marshal logger.MarshalFunc
|
|
|
- createDecoder makeDecoderFunc
|
|
|
+ createDecoder MakeDecoderFn
|
|
|
getTailReader GetTailReaderFunc
|
|
|
perms os.FileMode
|
|
|
}
|
|
|
|
|
|
-type makeDecoderFunc func(rdr io.Reader) func() (*logger.Message, error)
|
|
|
+// MakeDecoderFn creates a decoder
|
|
|
+type MakeDecoderFn func(rdr io.Reader) Decoder
|
|
|
+
|
|
|
+// Decoder is for reading logs
|
|
|
+// It is created by the log reader by calling the `MakeDecoderFunc`
|
|
|
+type Decoder interface {
|
|
|
+ // Reset resets the decoder
|
|
|
+ // Reset is called for certain events, such as log rotations
|
|
|
+ Reset(io.Reader)
|
|
|
+ // Decode decodes the next log messeage from the stream
|
|
|
+ Decode() (*logger.Message, error)
|
|
|
+ // Close signals to the decoder that it can release whatever resources it was using.
|
|
|
+ Close()
|
|
|
+}
|
|
|
|
|
|
// SizeReaderAt defines a ReaderAt that also reports its size.
|
|
|
// This is used for tailing log files.
|
|
@@ -110,7 +123,7 @@ type SizeReaderAt interface {
|
|
|
type GetTailReaderFunc func(ctx context.Context, f SizeReaderAt, nLogLines int) (rdr io.Reader, nLines int, err error)
|
|
|
|
|
|
// NewLogFile creates new LogFile
|
|
|
-func NewLogFile(logPath string, capacity int64, maxFiles int, compress bool, marshaller logger.MarshalFunc, decodeFunc makeDecoderFunc, perms os.FileMode, getTailReader GetTailReaderFunc) (*LogFile, error) {
|
|
|
+func NewLogFile(logPath string, capacity int64, maxFiles int, compress bool, marshaller logger.MarshalFunc, decodeFunc MakeDecoderFn, perms os.FileMode, getTailReader GetTailReaderFunc) (*LogFile, error) {
|
|
|
log, err := openFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, perms)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
@@ -314,6 +327,9 @@ func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher)
|
|
|
}
|
|
|
defer currentFile.Close()
|
|
|
|
|
|
+ dec := w.createDecoder(nil)
|
|
|
+ defer dec.Close()
|
|
|
+
|
|
|
currentChunk, err := newSectionReader(currentFile)
|
|
|
if err != nil {
|
|
|
w.mu.RUnlock()
|
|
@@ -359,7 +375,7 @@ func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher)
|
|
|
readers = append(readers, currentChunk)
|
|
|
}
|
|
|
|
|
|
- tailFiles(readers, watcher, w.createDecoder, w.getTailReader, config)
|
|
|
+ tailFiles(readers, watcher, dec, w.getTailReader, config)
|
|
|
closeFiles()
|
|
|
|
|
|
w.mu.RLock()
|
|
@@ -373,7 +389,7 @@ func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher)
|
|
|
|
|
|
notifyRotate := w.notifyRotate.Subscribe()
|
|
|
defer w.notifyRotate.Evict(notifyRotate)
|
|
|
- followLogs(currentFile, watcher, notifyRotate, w.createDecoder, config.Since, config.Until)
|
|
|
+ followLogs(currentFile, watcher, notifyRotate, dec, config.Since, config.Until)
|
|
|
}
|
|
|
|
|
|
func (w *LogFile) openRotatedFiles(config logger.ReadConfig) (files []*os.File, err error) {
|
|
@@ -479,7 +495,7 @@ func newSectionReader(f *os.File) (*io.SectionReader, error) {
|
|
|
return io.NewSectionReader(f, 0, size), nil
|
|
|
}
|
|
|
|
|
|
-func tailFiles(files []SizeReaderAt, watcher *logger.LogWatcher, createDecoder makeDecoderFunc, getTailReader GetTailReaderFunc, config logger.ReadConfig) {
|
|
|
+func tailFiles(files []SizeReaderAt, watcher *logger.LogWatcher, dec Decoder, getTailReader GetTailReaderFunc, config logger.ReadConfig) {
|
|
|
nLines := config.Tail
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
@@ -512,9 +528,10 @@ func tailFiles(files []SizeReaderAt, watcher *logger.LogWatcher, createDecoder m
|
|
|
}
|
|
|
|
|
|
rdr := io.MultiReader(readers...)
|
|
|
- decodeLogLine := createDecoder(rdr)
|
|
|
+ dec.Reset(rdr)
|
|
|
+
|
|
|
for {
|
|
|
- msg, err := decodeLogLine()
|
|
|
+ msg, err := dec.Decode()
|
|
|
if err != nil {
|
|
|
if errors.Cause(err) != io.EOF {
|
|
|
watcher.Err <- err
|
|
@@ -535,8 +552,8 @@ func tailFiles(files []SizeReaderAt, watcher *logger.LogWatcher, createDecoder m
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan interface{}, createDecoder makeDecoderFunc, since, until time.Time) {
|
|
|
- decodeLogLine := createDecoder(f)
|
|
|
+func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan interface{}, dec Decoder, since, until time.Time) {
|
|
|
+ dec.Reset(f)
|
|
|
|
|
|
name := f.Name()
|
|
|
fileWatcher, err := watchFile(name)
|
|
@@ -567,7 +584,7 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
|
|
|
if err := fileWatcher.Add(name); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- decodeLogLine = createDecoder(f)
|
|
|
+ dec.Reset(f)
|
|
|
return nil
|
|
|
}
|
|
|
|
|
@@ -578,7 +595,7 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
|
|
|
case e := <-fileWatcher.Events():
|
|
|
switch e.Op {
|
|
|
case fsnotify.Write:
|
|
|
- decodeLogLine = createDecoder(f)
|
|
|
+ dec.Reset(f)
|
|
|
return nil
|
|
|
case fsnotify.Rename, fsnotify.Remove:
|
|
|
select {
|
|
@@ -648,7 +665,7 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
|
|
|
|
|
|
// main loop
|
|
|
for {
|
|
|
- msg, err := decodeLogLine()
|
|
|
+ msg, err := dec.Decode()
|
|
|
if err != nil {
|
|
|
if err := handleDecodeErr(err); err != nil {
|
|
|
if err == errDone {
|