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.
74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
package cli
|
|
|
|
import (
|
|
"os"
|
|
"sync/atomic"
|
|
|
|
"github.com/Control-D-Inc/ctrld/internal/router"
|
|
)
|
|
|
|
// logPathFile is the open log_path file. The header renderer and the log
|
|
// readers need it, and both run outside this file.
|
|
var logPathFile atomic.Pointer[rotatingFile]
|
|
|
|
// pendingLogPathRotation holds the rotation of a start-time backup. The
|
|
// logger reaches no file at that point, so initLogging reports it later.
|
|
var pendingLogPathRotation atomic.Pointer[logRotation]
|
|
|
|
// openLogPathWriter opens the log_path file of this run and stores it for the
|
|
// header renderer and the log readers. It returns nil when no log_path is set.
|
|
// A start calls it more than once, so a call for the file that is already open
|
|
// keeps that file: a second open would put a second header in it.
|
|
func openLogPathWriter(doBackup bool) *rotatingFile {
|
|
logFilePath := normalizeLogFilePath(cfg.Service.LogPath)
|
|
if logFilePath == "" {
|
|
return nil
|
|
}
|
|
budget := debugLogBudget(&cfg.Service, router.Name() != "")
|
|
rf := logPathFile.Load()
|
|
if rf == nil || rf.currentPath() != logFilePath {
|
|
rf = newLogPathFile(logFilePath, budget)
|
|
} else {
|
|
rf.setBudget(budget)
|
|
}
|
|
if doBackup {
|
|
backupLogPathFile(rf)
|
|
}
|
|
return rf
|
|
}
|
|
|
|
// newLogPathFile opens path and puts it in place of the file of an earlier
|
|
// call. A ctrld that cannot write the log file its operator asked for leaves
|
|
// no record of the run, so the open failure ends the process.
|
|
func newLogPathFile(path string, budget logBudget) *rotatingFile {
|
|
rf, err := newRotatingFile(path, budget, nil)
|
|
if err != nil {
|
|
mainLog.Load().Error().Msgf("failed to create log file: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
rf.onRotate = emitLogRotated
|
|
if old := logPathFile.Swap(rf); old != nil {
|
|
_ = old.close()
|
|
}
|
|
return rf
|
|
}
|
|
|
|
// backupLogPathFile moves the file of an earlier run away, so no run
|
|
// overwrites another.
|
|
func backupLogPathFile(rf *rotatingFile) {
|
|
if !logFileHasContent(rf.currentPath()) {
|
|
return
|
|
}
|
|
record, err := rf.rotateNow()
|
|
if err != nil {
|
|
mainLog.Load().Error().Msgf("could not backup old log file: %v", err)
|
|
return
|
|
}
|
|
pendingLogPathRotation.Store(record)
|
|
}
|
|
|
|
func logFileHasContent(path string) bool {
|
|
st, err := os.Stat(path)
|
|
return err == nil && st.Size() > 0
|
|
}
|