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,14 +223,14 @@ 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
- return fmt .Errorf ("Failed to detect creation of %s: %s" , tail .Filename , err )
229
+ return fmt .Errorf ("failed to detect creation of %s: %s" , tail .Filename , err )
228
230
}
229
231
continue
230
232
}
231
- return fmt .Errorf ("Unable to open file %s: %s" , tail .Filename , err )
233
+ return fmt .Errorf ("unable to open file %s: %s" , tail .Filename , err )
232
234
}
233
235
break
234
236
}
@@ -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,23 @@ 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
+ // min of 0 and ret - tail.Location.Offset
298
+ // if ret - tail.Location.Offset is negative, then 0 is returned
299
+ // otherwise ret - tail.Location.Offset is returned
300
+
301
+ offset = int64 (math .Min (0 , float64 (ret )- math .Abs (float64 (offset ))))
302
+ }
303
+
304
+ if _ , err := tail .file .Seek (offset , tail .Location .Whence ); err != nil {
305
+ _ = tail .Killf ("Seek error on %s: %s" , tail .Filename , err )
290
306
return
291
307
}
292
308
}
@@ -312,7 +328,7 @@ func (tail *Tail) tailFileSync() {
312
328
if cooloff {
313
329
// Wait a second before seeking till the end of
314
330
// file when rate limit is reached.
315
- msg := ( "Too much log activity; waiting a second before resuming tailing")
331
+ msg := "too much log activity; waiting a second before resuming tailing"
316
332
offset , _ := tail .Tell ()
317
333
tail .Lines <- & Line {msg , tail .lineNum , SeekInfo {Offset : offset }, time .Now (), errors .New (msg )}
318
334
select {
@@ -346,7 +362,7 @@ func (tail *Tail) tailFileSync() {
346
362
// implementation (inotify or polling).
347
363
err := tail .waitForChanges ()
348
364
if err != nil {
349
- if err != ErrStop {
365
+ if ! errors . Is ( err , ErrStop ) {
350
366
tail .Kill (err )
351
367
}
352
368
return
@@ -359,7 +375,7 @@ func (tail *Tail) tailFileSync() {
359
375
360
376
select {
361
377
case <- tail .Dying ():
362
- if tail .Err () == errStopAtEOF {
378
+ if errors . Is ( tail .Err (), errStopAtEOF ) {
363
379
continue
364
380
}
365
381
return
0 commit comments