backend/analyzer/LiveUpdate.go (81 lines of code) (raw):
package analyzer
import (
"github.com/nxadm/tail"
wailsruntime "github.com/wailsapp/wails/v2/pkg/runtime"
"io"
"log"
"os"
)
func (a *Analyzer) EnableLogsLiveUpdate() {
if len(a.fileWatchers) > 0 {
log.Println("Logs live update already enabled")
for _, watcher := range a.fileWatchers {
log.Printf("file watcher: %v", watcher)
}
return
}
for entityIndex, entity := range a.DynamicEntities {
for path, instanceProperties := range entity.entityInstances {
if instanceProperties.Visible {
if entity.GetChangeablePath != nil {
if changeablePath := entity.GetChangeablePath(path); changeablePath != "" {
if s, err := os.Stat(changeablePath); !s.IsDir() && err == nil && entity.ConvertStringToLogs != nil {
go a.addWatcher(changeablePath, entityIndex)
}
}
}
}
}
}
}
func (a *Analyzer) addWatcher(logFile string, entityIndex int) {
for _, watcher := range a.fileWatchers {
if watcher.Filename == logFile {
return
}
}
t, err := tail.TailFile(logFile, tail.Config{
Follow: true,
Poll: true,
Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekEnd}, // <- line changed
})
if err != nil {
log.Println(err)
}
a.fileWatchers = append(a.fileWatchers, t)
log.Printf("Enabled File watcher for: %v", logFile)
previousLogEntry := ""
// t.Lines channel sends new lines of a file to "for" loop.
// Inside the loop, lines are being checked by ConvertStringToLogs function.
// If a line could be converted to log entry (ConvertStringToLogs return nil error), it is being remembered as previousLogEntry.
// If [the next line is also a log entry], previousLogEntry is being appended to the logs entry list. If next line is the last line of file, it also is being appended to the logs entry list.
// If [the next line is not a log entry], it is being appended to the previous log line (as it is part of the same log entry).
for line := range t.Lines {
f, _ := os.Open(t.Filename)
seek, _ := f.Seek(0, 2)
lineIsLast := line.SeekInfo.Offset == seek
if _, err := a.DynamicEntities[entityIndex].ConvertStringToLogs(line.Text); err == nil {
if len(previousLogEntry) != 0 {
a.attachToLogsStruct(previousLogEntry, entityIndex, t.Filename)
}
if lineIsLast {
a.attachToLogsStruct(line.Text, entityIndex, t.Filename)
previousLogEntry = ""
} else {
previousLogEntry = line.Text
}
} else {
previousLogEntry = previousLogEntry + "\n" + line.Text
if lineIsLast {
a.attachToLogsStruct(previousLogEntry, entityIndex, t.Filename)
previousLogEntry = ""
}
}
}
}
func (a *Analyzer) attachToLogsStruct(s string, i int, path string) {
name := a.DynamicEntities[i].Name
properties := a.DynamicEntities[i].entityInstances[path]
l, e := a.DynamicEntities[i].ConvertStringToLogs(s)
if e == nil {
a.AggregatedLogs.Append(name, properties, l)
wailsruntime.EventsEmit(*a.Context, "LogsUpdated", l.ConvertToHTML())
} else {
log.Printf("Cannot convert string to logs: %s \n string: %s", e, s)
}
}