// errorChecks checks how the given error should be handled based on the config options func (r *LogFile) errorChecks(err error) error { if err != io.EOF { logp.Err("Unexpected state reading from %s; error: %s", r.fs.Name(), err) return err } // Stdin is not continuable if !r.fs.Continuable() { logp.Debug("harvester", "Source is not continuable: %s", r.fs.Name()) return err } if err == io.EOF && r.config.CloseEOF { return err } // Refetch fileinfo to check if the file was truncated or disappeared. // Errors if the file was removed/rotated after reading and before // calling the stat function info, statErr := r.fs.Stat() if statErr != nil { logp.Err("Unexpected error reading from %s; error: %s", r.fs.Name(), statErr) return statErr } // check if file was truncated if info.Size() < r.offset { logp.Debug("harvester", "File was truncated as offset (%d) > size (%d): %s", r.offset, info.Size(), r.fs.Name()) return ErrFileTruncate } // Check file wasn't read for longer then CloseInactive age := time.Since(r.lastTimeRead) if age > r.config.CloseInactive { return ErrInactive } if r.config.CloseRenamed { // Check if the file can still be found under the same path if !file.IsSameFile(r.fs.Name(), info) { return ErrRenamed } } if r.config.CloseRemoved { // Check if the file name exists. See https://github.com/elastic/filebeat/issues/93 _, statErr := os.Stat(r.fs.Name()) // Error means file does not exist. if statErr != nil { return ErrRemoved } } return nil }
func (r *logFileReader) Read(buf []byte) (int, error) { for { select { case <-r.done: return 0, nil default: } n, err := r.fs.Read(buf) if n > 0 { r.offset += int64(n) r.lastTimeRead = time.Now() } // reset backoff if err == nil { r.backoff = r.config.BackoffDuration return n, nil } if err == io.EOF && r.config.CloseEOF { return n, err } // Stdin is not continuable if err != io.EOF || !r.fs.Continuable() { logp.Err("Unexpected state reading from %s; error: %s", r.fs.Name(), err) return n, err } // Refetch fileinfo to check if the file was truncated or disappeared. // Errors if the file was removed/rotated after reading and before // calling the stat function info, statErr := r.fs.Stat() if statErr != nil { logp.Err("Unexpected error reading from %s; error: %s", r.fs.Name(), statErr) return n, statErr } // handle fails if file was truncated if info.Size() < r.offset { logp.Debug("harvester", "File was truncated as offset (%s) > size (%s): %s", r.offset, info.Size(), r.fs.Name()) return n, ErrFileTruncate } age := time.Since(r.lastTimeRead) if age > r.config.CloseOlder { // If the file hasn't change for longer then maxInactive, harvester stops // and file handle will be closed. return n, ErrInactive } if r.config.CloseRenamed { // Check if the file can still be found under the same path if !file.IsSameFile(r.fs.Name(), info) { return n, ErrRenamed } } if r.config.CloseRemoved { // Check if the file name exists. See https://github.com/elastic/filebeat/issues/93 _, statErr := os.Stat(r.fs.Name()) // Error means file does not exist. if statErr != nil { return n, ErrRemoved } } if err != io.EOF { logp.Err("Unexpected state reading from %s; error: %s", r.fs.Name(), err) } logp.Debug("harvester", "End of file reached: %s; Backoff now.", r.fs.Name()) buf = buf[n:] if len(buf) == 0 { return n, nil } r.wait() } }
func (r *logFileReader) Read(buf []byte) (int, error) { for { select { case <-r.done: return 0, nil default: } n, err := r.fs.Read(buf) if n > 0 { r.offset += int64(n) r.lastTimeRead = time.Now() } if err == nil { // reset backoff r.backoff = r.config.BackoffDuration return n, nil } continuable := r.fs.Continuable() if err == io.EOF && !continuable { logp.Info("Reached end of file: %s", r.fs.Name()) return n, err } if err != io.EOF || !continuable { logp.Err("Unexpected state reading from %s; error: %s", r.fs.Name(), err) return n, err } // Refetch fileinfo to check if the file was truncated or disappeared. // Errors if the file was removed/rotated after reading and before // calling the stat function info, statErr := r.fs.Stat() if statErr != nil { logp.Err("Unexpected error reading from %s; error: %s", r.fs.Name(), statErr) return n, statErr } // handle fails if file was truncated if info.Size() < r.offset { logp.Debug("harvester", "File was truncated as offset (%s) > size (%s): %s", r.offset, info.Size(), r.fs.Name()) return n, ErrFileTruncate } age := time.Since(r.lastTimeRead) if age > r.config.CloseOlder { // If the file hasn't change for longer then maxInactive, harvester stops // and file handle will be closed. return n, ErrInactive } if r.config.ForceClose { // Check if the file name exists (see #93) _, statErr := os.Stat(r.fs.Name()) // Error means file does not exist. If no error, check if same file. If // not close as rotated. if statErr != nil || !file.IsSameFile(r.fs.Name(), info) { logp.Info("Force close file: %s; error: %s", r.fs.Name(), statErr) // Return directly on windows -> file is closing return n, ErrForceClose } } if err != io.EOF { logp.Err("Unexpected state reading from %s; error: %s", r.fs.Name(), err) } logp.Debug("harvester", "End of file reached: %s; Backoff now.", r.fs.Name()) buf = buf[n:] if len(buf) == 0 { return n, nil } r.wait() } }