summaryrefslogtreecommitdiff
path: root/pkg/tailfile/tailfile.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tailfile/tailfile.go')
-rw-r--r--pkg/tailfile/tailfile.go61
1 files changed, 61 insertions, 0 deletions
diff --git a/pkg/tailfile/tailfile.go b/pkg/tailfile/tailfile.go
new file mode 100644
index 0000000000..2ffd36d258
--- /dev/null
+++ b/pkg/tailfile/tailfile.go
@@ -0,0 +1,61 @@
+package tailfile
+
+import (
+ "bytes"
+ "errors"
+ "os"
+)
+
+const blockSize = 1024
+
+var eol = []byte("\n")
+var ErrNonPositiveLinesNumber = errors.New("Lines number must be positive")
+
+//TailFile returns last n lines of file f
+func TailFile(f *os.File, n int) ([][]byte, error) {
+ if n <= 0 {
+ return nil, ErrNonPositiveLinesNumber
+ }
+ size, err := f.Seek(0, os.SEEK_END)
+ if err != nil {
+ return nil, err
+ }
+ block := -1
+ var data []byte
+ var cnt int
+ for {
+ var b []byte
+ step := int64(block * blockSize)
+ left := size + step // how many bytes to beginning
+ if left < 0 {
+ if _, err := f.Seek(0, os.SEEK_SET); err != nil {
+ return nil, err
+ }
+ b = make([]byte, blockSize+left)
+ if _, err := f.Read(b); err != nil {
+ return nil, err
+ }
+ data = append(b, data...)
+ break
+ } else {
+ b = make([]byte, blockSize)
+ if _, err := f.Seek(step, os.SEEK_END); err != nil {
+ return nil, err
+ }
+ if _, err := f.Read(b); err != nil {
+ return nil, err
+ }
+ data = append(b, data...)
+ }
+ cnt += bytes.Count(b, eol)
+ if cnt > n {
+ break
+ }
+ block--
+ }
+ lines := bytes.Split(data, eol)
+ if n < len(lines) {
+ return lines[len(lines)-n-1 : len(lines)-1], nil
+ }
+ return lines[:len(lines)-1], nil
+}