mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-10-12 01:58:46 +02:00
ctrld keeps a second log file, ctrld-journal.log, next to ctrld.log. The journal holds all warnings and errors and each event with the field journal=true. It stays on disk after a start of the service and after a self-upgrade. Each log file starts with a Log header line. Each log send upload starts with the same line, made at send time, and has a limit of about 16 MB.
81 lines
1.8 KiB
Go
81 lines
1.8 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
// logTailPollInterval is the time between two reads of a tailed log file.
|
|
const logTailPollInterval = 200 * time.Millisecond
|
|
|
|
// followLogFile streams the lines of path until ctx ends. It first sends the
|
|
// last numLines lines, or starts at the end when numLines is 0. A rotation
|
|
// moves the file away or truncates it, so the poll reopens the path when the
|
|
// file behind it changes or shrinks.
|
|
func followLogFile(ctx context.Context, w io.Writer, flusher http.Flusher, path string, numLines int) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer func() { f.Close() }()
|
|
|
|
if numLines > 0 {
|
|
if tail := tailFileLastLines(f, numLines); len(tail) > 0 {
|
|
w.Write(tail)
|
|
flusher.Flush()
|
|
}
|
|
} else {
|
|
f.Seek(0, io.SeekEnd)
|
|
}
|
|
|
|
buf := make([]byte, 4096)
|
|
ticker := time.NewTicker(logTailPollInterval)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
n, err := f.Read(buf)
|
|
if n > 0 {
|
|
if _, werr := w.Write(buf[:n]); werr != nil {
|
|
return
|
|
}
|
|
flusher.Flush()
|
|
}
|
|
if err != nil && err != io.EOF {
|
|
return
|
|
}
|
|
if n == 0 && logFileReplaced(f, path) {
|
|
reopened, err := os.Open(path)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
f.Close()
|
|
f = reopened
|
|
}
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// logFileReplaced reports whether path names another file than f, or a file
|
|
// shorter than the read position. Both mean that a rotation happened.
|
|
func logFileReplaced(f *os.File, path string) bool {
|
|
current, err := os.Stat(path)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
open, err := f.Stat()
|
|
if err != nil {
|
|
return true
|
|
}
|
|
if !os.SameFile(current, open) {
|
|
return true
|
|
}
|
|
position, err := f.Seek(0, io.SeekCurrent)
|
|
return err == nil && current.Size() < position
|
|
}
|