func tailFile(filename string, config tail.Config, done chan bool) { defer func() { done <- true }() t, err := tail.TailFile(filename, config) if err != nil { fmt.Println(err) return } for line := range t.Lines { fmt.Println(line.Text) } err = t.Wait() if err != nil { fmt.Println(err) } }
// Read old log lines from a logfile. func (l *Log) Read(lines int, follow bool, ch chan Data, done chan struct{}) error { name := l.l.Filename var seek int64 if lines == 0 { f, err := os.Open(name) defer f.Close() if err != nil { return err } if seek, err = f.Seek(0, os.SEEK_END); err != nil { return err } } else if lines == -1 { // return all lines dir := filepath.Dir(name) files, err := ioutil.ReadDir(dir) if err != nil { return err } basename := filepath.Base(name) ext := filepath.Ext(basename) id := strings.TrimSuffix(basename, ext) for _, f := range files { if !(strings.HasPrefix(f.Name(), id+"-") && strings.HasSuffix(f.Name(), ext)) { continue } t, err := tail.TailFile(filepath.Join(dir, f.Name()), tail.Config{ Logger: tail.DiscardingLogger, }) if err != nil { return err } for line := range t.Lines { data := Data{} if err := json.Unmarshal([]byte(line.Text), &data); err != nil { return err } ch <- data } } } t, err := tail.TailFile(name, tail.Config{ Follow: follow, ReOpen: follow, Logger: tail.DiscardingLogger, Location: &tail.SeekInfo{ Offset: seek, Whence: os.SEEK_SET, }, }) if err != nil { return err } outer: for { select { case line, ok := <-t.Lines: if !ok { break outer } data := Data{} if err := json.Unmarshal([]byte(line.Text), &data); err != nil { return err } ch <- data case <-done: break outer case <-time.After(200 * time.Millisecond): if !l.closed { continue } break outer } } close(ch) // send a close event so we know everything was read return nil }