in internal/utils/file/file.go [227:282]
func ReadLastNLines(path string, n int) ([]string, error) {
galog.Debugf("Reading last %d lines of file %q", n, path)
f, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("failed to open file %q: %w", path, err)
}
defer f.Close()
stat, err := f.Stat()
if err != nil {
return nil, fmt.Errorf("failed to stat file %q: %w", path, err)
}
size := stat.Size()
bufferSize := int64(1024)
buffer := make([]byte, bufferSize)
var lines []string
var chunk []byte
for offset := size - 1; offset >= 0; offset -= bufferSize {
start := offset - bufferSize
if start < 0 {
start = 0
}
readSize := int(offset - start + 1)
_, err := f.ReadAt(buffer[:readSize], start)
if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) {
return nil, err
}
for i := readSize - 1; i >= 0; i-- {
if buffer[i] == '\n' {
lines = append([]string{string(chunk)}, lines...)
chunk = nil
if len(lines) >= n {
return lines, nil
}
} else {
chunk = append([]byte{buffer[i]}, chunk...)
}
}
if len(chunk) > 0 {
lines = append([]string{string(chunk)}, lines...)
}
if len(lines) >= n {
return lines[len(lines)-n:], nil
}
}
return lines, nil
}