83 lines
1.8 KiB
Go
83 lines
1.8 KiB
Go
package app
|
||
|
||
import (
|
||
"io"
|
||
"os"
|
||
"strconv"
|
||
"strings"
|
||
)
|
||
|
||
// ---------------------------------------------------------------------
|
||
// tail helper
|
||
// ---------------------------------------------------------------------
|
||
|
||
const defaultTailMaxBytes = 512 * 1024
|
||
|
||
func tailFile(path string, maxLines int) []string {
|
||
if maxLines <= 0 {
|
||
return nil
|
||
}
|
||
|
||
// читаем лимит из env, если задан
|
||
maxBytes := defaultTailMaxBytes
|
||
if env := os.Getenv("SVPN_TAIL_MAX_BYTES"); env != "" {
|
||
if n, err := strconv.Atoi(env); err == nil && n > 0 {
|
||
maxBytes = n
|
||
}
|
||
}
|
||
|
||
f, err := os.Open(path)
|
||
if err != nil {
|
||
// файла нет или нет прав — просто ничего не отдаём
|
||
return nil
|
||
}
|
||
defer f.Close()
|
||
|
||
fi, err := f.Stat()
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
size := fi.Size()
|
||
if size <= 0 {
|
||
return nil
|
||
}
|
||
|
||
// с какого смещения читаем хвост
|
||
start := int64(0)
|
||
if size > int64(maxBytes) {
|
||
start = size - int64(maxBytes)
|
||
}
|
||
|
||
// двигаем указатель в файле
|
||
if _, err := f.Seek(start, io.SeekStart); err != nil {
|
||
return nil
|
||
}
|
||
|
||
// читаем хвост
|
||
data, err := io.ReadAll(f)
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
|
||
// режем по строкам
|
||
lines := strings.Split(string(data), "\n")
|
||
|
||
// если мы начали читать с середины файла (start > 0),
|
||
// первая строка почти наверняка обрезана — выбрасываем её.
|
||
if start > 0 && len(lines) > 0 {
|
||
lines = lines[1:]
|
||
}
|
||
|
||
// убираем финальную пустую строку, если есть
|
||
if n := len(lines); n > 0 && lines[n-1] == "" {
|
||
lines = lines[:n-1]
|
||
}
|
||
|
||
// берём только последние maxLines
|
||
if len(lines) > maxLines {
|
||
lines = lines[len(lines)-maxLines:]
|
||
}
|
||
|
||
return lines
|
||
}
|