func (i *Tail) translateConfig(original *TailConfig) tail.Config { config := tail.Config{Follow: true, ReOpen: true} if original.MustExist { config.MustExist = true } if original.Poll { config.Poll = true } if original.LimitRate > 0 { config.RateLimiter = ratelimiter.NewLeakyBucket( uint16(original.LimitRate), time.Second, ) } position := i.readPosition() if position > 0 { config.Location = &tail.SeekInfo{Offset: position, Whence: 0} } return config }
func tailOptionsToConfig(tailOptions TailOptions) tail.Config { config := tail.Config{ ReOpen: tailOptions.ReOpen, MustExist: tailOptions.MustExist, Poll: tailOptions.Poll, Pipe: tailOptions.Pipe, Follow: tailOptions.Follow, } if tailOptions.Location != nil { config.Location = &tail.SeekInfo{ Offset: tailOptions.Location.Offset, Whence: tailOptions.Location.Whence, } } return config }
func (v *FileTail) watcher() { log.Printf("[INFO] [%s] File watcher started", v.tag) for { for file, _ := range v.files { select { case <-v.files[file].Dying(): log.Printf("[DEBUG] [%s] File \"%s\" closed", v.tag, file) delete(v.files, file) default: continue } } //Search for new files for _, path := range v.paths { f, _ := filepath.Glob(path) for _, file := range f { if _, ok := v.files[file]; !ok { log.Printf("[DEBUG] [%s] Found file \"%s\"", v.tag, file) tc := tail.Config{Follow: true, ReOpen: false, MustExist: true, Poll: true, Logger: tail.DiscardingLogger} if s, err := ioutil.ReadFile(file + ".pos"); err == nil { s := strings.Split(string(s), "\n") if len(s) == 2 { if ctime, err := strconv.Atoi(s[0]); err == nil && int64(ctime) == ctimeFile(file) { if pos, err := strconv.Atoi(s[1]); err == nil { tc.Location = &tail.SeekInfo{Whence: os.SEEK_CUR, Offset: int64(pos)} log.Printf("[DEBUG] [%s] Restoring position %d in file \"%s\"", v.tag, pos, file) } } } } t, err := tail.TailFile(file, tc) if err == nil { go v.worker(t) v.files[file] = t } } } } time.Sleep(time.Second) } }