blob: e7bdd92cd6de04707cf4e485f61fd9c11c4bc8ee [file] [log] [blame]
package logagents
import (
"fmt"
"go.skia.org/infra/go/sklog"
"go.skia.org/infra/skolo/go/logparser"
)
// The raspberry pi might run out of memory if we don't log in smallish batches.
const BATCH_REPORT_SIZE = 100
// rolloverLog watches two files, the primary log and the first rollover log (e.g. log.1)
// It hashes them every time it scans and uses that information to detect if any changes happened
// and/or if the logs rolled over.
type rolloverLog struct {
Name string
Parse logparser.Parser `json:"-"`
LastLine int
LogPath string
LogHash string
RolloverPath string
RolloverHash string
IsFirstScan bool
}
func NewRollover(parse logparser.Parser, reportName, logFile, rolloverFile string) LogScanner {
log := &rolloverLog{
Name: reportName,
Parse: parse,
LogPath: logFile,
RolloverPath: rolloverFile,
IsFirstScan: true,
}
if err := readFromPersistenceFile(reportName, log); err != nil {
sklog.Warningf("Could not read from persistence file for %s. Starting with default values: %s", reportName, err)
}
return log
}
func (r *rolloverLog) ReportName() string {
return r.Name
}
func (r *rolloverLog) Scan(client sklog.CloudLogger) error {
logC, logH, err := readAndHashFile(r.LogPath)
if err != nil {
return fmt.Errorf("Problem reading log file %s: %s", r.LogPath, err)
}
sklog.Infof("Read %s with hash %s", r.LogPath, logH)
rollC, rollH, err := readAndHashFile(r.RolloverPath)
if err != nil {
return fmt.Errorf("Problem reading rollover file %s: %s", r.RolloverPath, err)
}
if r.IsFirstScan {
// This was the first scan and there was something already there.
// We will not log that stuff now.
r.RolloverHash = rollH
}
if r.RolloverHash != rollH {
// We rolled over
sklog.Infof("Detected rollover to file %s", r.RolloverPath)
r.RolloverHash = rollH
lp := r.Parse(rollC)
r.reportLogs(client, lp, r.LastLine)
r.LastLine = 0
}
if r.LogHash != logH {
r.LogHash = logH
lp := r.Parse(logC)
start := r.LastLine
if r.IsFirstScan && lp.Len() > 1000 {
// Only log the first 1000 lines of a new log file, to avoid OOM problems.
start = lp.Len() - 1000
}
sklog.Infof("Starting %s log at line %d out of %d", r.ReportName(), start, lp.Len())
r.reportLogs(client, lp, start)
r.LastLine = lp.CurrLine()
}
r.IsFirstScan = false
sklog.Infof("Finished %s at line %d", r.ReportName(), r.LastLine)
return writeToPersistenceFile(r.ReportName(), r)
}
func (r *rolloverLog) reportLogs(client sklog.CloudLogger, lp logparser.ParsedLog, startLine int) {
lp.Start(startLine)
logs := make([]*sklog.LogPayload, 0, BATCH_REPORT_SIZE)
for log := lp.ReadAndNext(); log != nil; log = lp.ReadAndNext() {
logs = append(logs, log)
if len(logs) >= BATCH_REPORT_SIZE {
client.BatchCloudLog(r.ReportName(), logs...)
logs = nil
}
}
client.BatchCloudLog(r.ReportName(), logs...)
}