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