parent
1c31b19fd2
commit
e73c30689c
@ -1,3 +0,0 @@ |
||||
# util |
||||
|
||||
Functions and primitives I use. Copy code instead of depending on this library. |
@ -1,4 +1,4 @@ |
||||
package util |
||||
package batch |
||||
|
||||
import ( |
||||
"time" |
2
vendor/github.com/jtagcat/util/go.go → vendor/github.com/jtagcat/util/std/go.go
generated
vendored
2
vendor/github.com/jtagcat/util/go.go → vendor/github.com/jtagcat/util/std/go.go
generated
vendored
@ -1,4 +1,4 @@ |
||||
package util |
||||
package std |
||||
|
||||
import "sync" |
||||
|
@ -1,4 +1,4 @@ |
||||
package util |
||||
package std |
||||
|
||||
import "strings" |
||||
|
@ -0,0 +1,143 @@ |
||||
package tail |
||||
|
||||
import ( |
||||
"bufio" |
||||
"context" |
||||
"errors" |
||||
"io" |
||||
"os" |
||||
"sync" |
||||
) |
||||
|
||||
type Line struct { |
||||
Filename *string |
||||
Bytes []byte |
||||
EndOffset int64 // io.SeekStart
|
||||
ReachedEOF bool |
||||
} |
||||
|
||||
type Tailable struct { |
||||
Name string |
||||
// os.Seek() on first open:
|
||||
Offset int64 |
||||
Whence int |
||||
|
||||
// loop-persisting
|
||||
existed bool |
||||
|
||||
// copied use
|
||||
wakeup chan struct{} |
||||
} |
||||
|
||||
type orderedLines struct { |
||||
c chan<- *Line |
||||
sync.Mutex // guarantee ordered lines across multiple files of same name
|
||||
} |
||||
|
||||
// Handles tailing a file within its lifespan
|
||||
func fileHandle(ctx context.Context, file Tailable, useOffset bool, lineChan *orderedLines, errChan chan<- error) { |
||||
f, err := os.Open(file.Name) |
||||
if err != nil && !errors.Is(err, os.ErrNotExist) { // ignore ErrNotExist, as it may have been race deleted
|
||||
errChan <- err |
||||
return |
||||
} |
||||
defer f.Close() |
||||
|
||||
var offset int64 |
||||
if useOffset { |
||||
offset, err = f.Seek(file.Offset, file.Whence) |
||||
if err != nil { |
||||
errChan <- err |
||||
return |
||||
} |
||||
} |
||||
|
||||
first, breakNext, b := true, false, bufio.NewReader(f) |
||||
for { |
||||
|
||||
select { |
||||
case <-ctx.Done(): |
||||
errChan <- ctx.Err() |
||||
return |
||||
default: |
||||
} |
||||
|
||||
if first { |
||||
first = false |
||||
} else { |
||||
offset, err = detectTruncation(f, offset) |
||||
if err != nil { |
||||
errChan <- err |
||||
return |
||||
} |
||||
} |
||||
|
||||
offset, err = readToEOF(b, &file.Name, offset, lineChan.c) |
||||
if err != nil { |
||||
errChan <- err |
||||
return |
||||
} |
||||
|
||||
if breakNext { |
||||
return |
||||
} |
||||
select { |
||||
case <-ctx.Done(): |
||||
case _, ok := <-file.wakeup: |
||||
if !ok { |
||||
fs, err := f.Stat() |
||||
if err != nil && !errors.Is(err, os.ErrNotExist) { |
||||
errChan <- ctx.Err() |
||||
return |
||||
} |
||||
|
||||
if err != nil || fs.Size() == offset { |
||||
return |
||||
} |
||||
|
||||
breakNext = true |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// offset is io.SeekStart
|
||||
func detectTruncation(f *os.File, offset int64) (int64, error) { |
||||
fs, err := f.Stat() |
||||
if err != nil && !errors.Is(err, os.ErrNotExist) { // ignore ErrNotExist, as it may have been race deleted
|
||||
return 0, err |
||||
} |
||||
|
||||
if fs.Size() < offset { |
||||
// file has been truncated
|
||||
return f.Seek(0, io.SeekStart) |
||||
} |
||||
|
||||
return offset, nil |
||||
} |
||||
|
||||
func readToEOF(buf *bufio.Reader, name *string, offset int64, c chan<- *Line) (int64, error) { |
||||
for { |
||||
b, err := buf.ReadBytes('\n') |
||||
offset += int64(len(b)) |
||||
|
||||
if err != nil && !errors.Is(err, io.EOF) { |
||||
return offset, err |
||||
} |
||||
|
||||
if err == nil { |
||||
b = b[:len(b)-1] // remove \n
|
||||
} |
||||
|
||||
c <- &Line{ |
||||
Filename: name, |
||||
Bytes: b, |
||||
EndOffset: offset, |
||||
ReachedEOF: err != nil, |
||||
} |
||||
|
||||
if err != nil { // EOF
|
||||
return offset, nil |
||||
} |
||||
} |
||||
} |
148
vendor/github.com/jtagcat/util/tail.go → vendor/github.com/jtagcat/util/tail/tail.go
generated
vendored
148
vendor/github.com/jtagcat/util/tail.go → vendor/github.com/jtagcat/util/tail/tail.go
generated
vendored
Loading…
Reference in new issue