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