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  }