github.com/wlan0/docker@v1.5.0/pkg/tailfile/tailfile.go (about) 1 package tailfile 2 3 import ( 4 "bytes" 5 "errors" 6 "os" 7 ) 8 9 const blockSize = 1024 10 11 var eol = []byte("\n") 12 var ErrNonPositiveLinesNumber = errors.New("Lines number must be positive") 13 14 //TailFile returns last n lines of file f 15 func TailFile(f *os.File, n int) ([][]byte, error) { 16 if n <= 0 { 17 return nil, ErrNonPositiveLinesNumber 18 } 19 size, err := f.Seek(0, os.SEEK_END) 20 if err != nil { 21 return nil, err 22 } 23 block := -1 24 var data []byte 25 var cnt int 26 for { 27 var b []byte 28 step := int64(block * blockSize) 29 left := size + step // how many bytes to beginning 30 if left < 0 { 31 if _, err := f.Seek(0, os.SEEK_SET); err != nil { 32 return nil, err 33 } 34 b = make([]byte, blockSize+left) 35 if _, err := f.Read(b); err != nil { 36 return nil, err 37 } 38 data = append(b, data...) 39 break 40 } else { 41 b = make([]byte, blockSize) 42 if _, err := f.Seek(step, os.SEEK_END); err != nil { 43 return nil, err 44 } 45 if _, err := f.Read(b); err != nil { 46 return nil, err 47 } 48 data = append(b, data...) 49 } 50 cnt += bytes.Count(b, eol) 51 if cnt > n { 52 break 53 } 54 block-- 55 } 56 lines := bytes.Split(data, eol) 57 if n < len(lines) { 58 return lines[len(lines)-n-1 : len(lines)-1], nil 59 } 60 return lines[:len(lines)-1], nil 61 }