2
2
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
3
3
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
4
4
5
- //nxadm/tail provides a Go library that emulates the features of the BSD `tail`
6
- //program. The library comes with full support for truncation/move detection as
7
- //it is designed to work with log rotation tools. The library works on all
8
- //operating systems supported by Go, including POSIX systems like Linux and
9
- //*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
5
+ // nxadm/tail provides a Go library that emulates the features of the BSD `tail`
6
+ // program. The library comes with full support for truncation/move detection as
7
+ // it is designed to work with log rotation tools. The library works on all
8
+ // operating systems supported by Go, including POSIX systems like Linux and
9
+ // *BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
10
10
package tail
11
11
12
12
import (
@@ -16,15 +16,17 @@ import (
16
16
"io"
17
17
"io/ioutil"
18
18
"log"
19
+ "math"
19
20
"os"
20
21
"strings"
21
22
"sync"
22
23
"time"
23
24
25
+ "gopkg.in/tomb.v1"
26
+
24
27
"github.com/nxadm/tail/ratelimiter"
25
28
"github.com/nxadm/tail/util"
26
29
"github.com/nxadm/tail/watch"
27
- "gopkg.in/tomb.v1"
28
30
)
29
31
30
32
var (
@@ -221,7 +223,7 @@ func (tail *Tail) reopen() error {
221
223
if os .IsNotExist (err ) {
222
224
tail .Logger .Printf ("Waiting for %s to appear..." , tail .Filename )
223
225
if err := tail .watcher .BlockUntilExists (& tail .Tomb ); err != nil {
224
- if err == tomb .ErrDying {
226
+ if errors . Is ( err , tomb .ErrDying ) {
225
227
return err
226
228
}
227
229
return fmt .Errorf ("Failed to detect creation of %s: %s" , tail .Filename , err )
@@ -275,7 +277,7 @@ func (tail *Tail) tailFileSync() {
275
277
// deferred first open.
276
278
err := tail .reopen ()
277
279
if err != nil {
278
- if err != tomb .ErrDying {
280
+ if ! errors . Is ( err , tomb .ErrDying ) {
279
281
tail .Kill (err )
280
282
}
281
283
return
@@ -284,9 +286,24 @@ func (tail *Tail) tailFileSync() {
284
286
285
287
// Seek to requested location on first open of the file.
286
288
if tail .Location != nil {
287
- _ , err := tail .file .Seek (tail .Location .Offset , tail .Location .Whence )
288
- if err != nil {
289
- tail .Killf ("Seek error on %s: %s" , tail .Filename , err )
289
+ offset := tail .Location .Offset
290
+ if tail .Location .Whence == io .SeekEnd && offset < 0 {
291
+ ret , err := tail .file .Seek (0 , io .SeekEnd )
292
+ if err != nil {
293
+ _ = tail .Killf ("Seek error on %s: %s" , tail .Filename , err )
294
+ return
295
+ }
296
+
297
+ // if ret > abs(offset), use offset
298
+ // otherwise, use ret
299
+
300
+ if ret < int64 (math .Abs (float64 (offset ))) {
301
+ offset = ret
302
+ }
303
+ }
304
+
305
+ if _ , err := tail .file .Seek (offset , tail .Location .Whence ); err != nil {
306
+ _ = tail .Killf ("Seek error on %s: %s" , tail .Filename , err )
290
307
return
291
308
}
292
309
}
@@ -312,7 +329,7 @@ func (tail *Tail) tailFileSync() {
312
329
if cooloff {
313
330
// Wait a second before seeking till the end of
314
331
// file when rate limit is reached.
315
- msg := ( "Too much log activity; waiting a second before resuming tailing" )
332
+ msg := "Too much log activity; waiting a second before resuming tailing"
316
333
offset , _ := tail .Tell ()
317
334
tail .Lines <- & Line {msg , tail .lineNum , SeekInfo {Offset : offset }, time .Now (), errors .New (msg )}
318
335
select {
@@ -346,7 +363,7 @@ func (tail *Tail) tailFileSync() {
346
363
// implementation (inotify or polling).
347
364
err := tail .waitForChanges ()
348
365
if err != nil {
349
- if err != ErrStop {
366
+ if ! errors . Is ( err , ErrStop ) {
350
367
tail .Kill (err )
351
368
}
352
369
return
@@ -359,7 +376,7 @@ func (tail *Tail) tailFileSync() {
359
376
360
377
select {
361
378
case <- tail .Dying ():
362
- if tail .Err () == errStopAtEOF {
379
+ if errors . Is ( tail .Err (), errStopAtEOF ) {
363
380
continue
364
381
}
365
382
return
0 commit comments