| 224 | } |
| 225 | |
| 226 | func (tail *Tail) tailFileSync() { |
| 227 | defer tail.Done() |
| 228 | defer tail.close() |
| 229 | |
| 230 | if !tail.MustExist { |
| 231 | // deferred first open. |
| 232 | err := tail.reopen() |
| 233 | if err != nil { |
| 234 | if err != tomb.ErrDying { |
| 235 | tail.Kill(err) |
| 236 | } |
| 237 | return |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | // Seek to requested location on first open of the file. |
| 242 | if tail.Location != nil { |
| 243 | _, err := tail.file.Seek(tail.Location.Offset, tail.Location.Whence) |
| 244 | tail.Logger.Printf("Seeked %s - %+v\n", tail.Filename, tail.Location) |
| 245 | if err != nil { |
| 246 | tail.Killf("Seek error on %s: %s", tail.Filename, err) |
| 247 | return |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | tail.openReader() |
| 252 | |
| 253 | var offset int64 = 0 |
| 254 | var err error |
| 255 | |
| 256 | // Read line by line. |
| 257 | for { |
| 258 | // do not seek in named pipes |
| 259 | if !tail.Pipe { |
| 260 | // grab the position in case we need to back up in the event of a half-line |
| 261 | offset, err = tail.Tell() |
| 262 | if err != nil { |
| 263 | tail.Kill(err) |
| 264 | return |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | line, err := tail.readLine() |
| 269 | |
| 270 | // Process `line` even if err is EOF. |
| 271 | if err == nil { |
| 272 | cooloff := !tail.sendLine(line) |
| 273 | if cooloff { |
| 274 | // Wait a second before seeking till the end of |
| 275 | // file when rate limit is reached. |
| 276 | msg := fmt.Sprintf( |
| 277 | "Too much log activity; waiting a second " + |
| 278 | "before resuming tailing") |
| 279 | tail.Lines <- &Line{msg, time.Now(), fmt.Errorf(msg)} |
| 280 | select { |
| 281 | case <-time.After(time.Second): |
| 282 | case <-tail.Dying(): |
| 283 | return |