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  }