github.com/netdata/go.d.plugin@v0.58.1/pkg/logs/lastline.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package logs 4 5 import ( 6 "errors" 7 "os" 8 9 "github.com/clbanning/rfile/v2" 10 ) 11 12 const DefaultMaxLineWidth = 4 * 1024 // assume disk block size is 4K 13 14 var ErrTooLongLine = errors.New("too long line") 15 16 // ReadLastLine returns the last line of the file and any read error encountered. 17 // It expects last line width <= maxLineWidth. 18 // If maxLineWidth <= 0, it defaults to DefaultMaxLineWidth. 19 func ReadLastLine(filename string, maxLineWidth int64) ([]byte, error) { 20 if maxLineWidth <= 0 { 21 maxLineWidth = DefaultMaxLineWidth 22 } 23 f, err := os.Open(filename) 24 if err != nil { 25 return nil, err 26 } 27 defer func() { _ = f.Close() }() 28 29 stat, _ := f.Stat() 30 endPos := stat.Size() 31 if endPos == 0 { 32 return []byte{}, nil 33 } 34 startPos := endPos - maxLineWidth 35 if startPos < 0 { 36 startPos = 0 37 } 38 buf := make([]byte, endPos-startPos) 39 n, err := f.ReadAt(buf, startPos) 40 if err != nil { 41 return nil, err 42 } 43 lnPos := 0 44 foundLn := false 45 for i := n - 2; i >= 0; i-- { 46 ch := buf[i] 47 if ch == '\n' { 48 foundLn = true 49 lnPos = i 50 break 51 } 52 } 53 if foundLn { 54 return buf[lnPos+1 : n], nil 55 } 56 if startPos == 0 { 57 return buf[0:n], nil 58 } 59 60 return nil, ErrTooLongLine 61 } 62 63 func ReadLastLines(filename string, n uint) ([]string, error) { 64 return rfile.Tail(filename, int(n)) 65 }