// read reads blocks of 4096 bytes from the File, sending lines to the // channel as it encounters newlines. If EOF is encountered, the partial line // is returned to be concatenated with on the next call. func (t *Tailer) read(f afero.File, partialIn string) (partialOut string, err error) { partial := partialIn b := make([]byte, 0, 4096) for { n, err := f.Read(b[:cap(b)]) b = b[:n] if err != nil { return partial, err } for i, width := 0, 0; i < len(b) && i < n; i += width { var rune rune rune, width = utf8.DecodeRune(b[i:]) switch { case rune != '\n': partial += string(rune) default: // send off line for processing t.lines <- partial // reset accumulator partial = "" } } } }
func (m *MemS3Fs) registerDirs(f afero.File) { var x = f.Name() for x != "/" { f := m.registerWithParent(f) if f == nil { break } x = f.Name() } }
func (t *Tailer) readForever(f afero.File) { var err error partial := "" for { partial, err = t.read(f, partial) // We want to exit at EOF, because the FD has been closed. if err != nil { glog.Infof("%s: %s", err, f.Name()) return } } }
func (m *MemS3Fs) findParent(f afero.File) afero.File { dirs, _ := path.Split(f.Name()) if len(dirs) > 1 { _, parent := path.Split(path.Clean(dirs)) if len(parent) > 0 { pfile, err := m.Open(parent) if err != nil { return pfile } } } return nil }
func (m *MemS3Fs) registerWithParent(f afero.File) afero.File { if f == nil { return nil } parent := m.findParent(f) if parent != nil { pmem := parent.(*InMemoryFile) pmem.memDir.Add(f) } else { pdir := filepath.Dir(path.Clean(f.Name())) m.Mkdir(pdir, 0777) } return parent }
func checkSize(t *testing.T, f afero.File, size int64) { dir, err := f.Stat() if err != nil { t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) } if dir.Size() != size { t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size) } }
func (t *Tailer) startNewFile(f afero.File, seekStart bool) error { fi, err := f.Stat() if err != nil { // Stat failed, log error and return. logErrors.Add(f.Name(), 1) return fmt.Errorf("Failed to stat %q: %s", f.Name(), err) } switch m := fi.Mode(); { case m&os.ModeType == 0: if seekStart { f.Seek(0, os.SEEK_SET) } else { f.Seek(0, os.SEEK_END) } err = t.w.Add(f.Name()) if err != nil { return fmt.Errorf("Adding a change watch failed on %q: %s", f.Name(), err) } // In case the new log has been written to already, attempt to read the // first lines. t.partials[f.Name()], err = t.read(f, "") if err != nil { if err == io.EOF { // Don't worry about EOF on first read, that's expected. break } return err } case m&os.ModeType == os.ModeNamedPipe: go t.readForever(f) default: return fmt.Errorf("Can't open files with mode %v: %s", m&os.ModeType, f.Name()) } t.filesLock.Lock() t.files[f.Name()] = f t.filesLock.Unlock() glog.Infof("Tailing %s", f.Name()) return nil }
func (m MemDirMap) Remove(f afero.File) { delete(m, f.Name()) }
func (m MemDirMap) Add(f afero.File) { m[f.Name()] = f }