jobwatch/app/state/log.go

189 lines
3.7 KiB
Go

package state
import (
"encoding/json"
"fmt"
"io/ioutil"
"jobwatch/types"
"log"
"os"
"path/filepath"
"strings"
)
type LogEntryState string
const MAX_LOG_ENTRIES = 2500
const MAX_LOG_SEND = 250
const (
LOG_OK LogEntryState = "O"
LOG_WARN LogEntryState = "W"
LOG_CRIT LogEntryState = "C"
LOG_UNKWN LogEntryState = "U"
)
type LogEntry struct {
Id int `json:"id"`
Date string `json:"date"`
State LogEntryState `json:"state"`
Text string `json:"text"`
}
type LogDb struct {
JobFullName string `json:"job_full_name"`
MaxSentByRemote map[string]int `json:"max_sent_by_remote"`
Entries []LogEntry `json:"entries"`
}
func LoadLog(logPath string) (*LogDb, error) {
if _, err := os.Stat(logPath); err != nil {
log.Println("Existing log not readable, creating new")
return &LogDb{}, nil
}
data, err := os.ReadFile(logPath)
if err != nil {
return nil, err
}
var logDb LogDb
err = json.Unmarshal(data, &logDb)
if err != nil {
return nil, fmt.Errorf("Error unmarshaling state: %v", err)
}
log.Println("existing log loaded")
return &logDb, nil
}
func (logDb LogDb) Save(logPath string) error {
data, err := json.MarshalIndent(logDb, " ", " ")
if err != nil {
return fmt.Errorf("Error marshaling state: %v", err)
}
if err := os.WriteFile(logPath, data, 0600); err != nil {
return fmt.Errorf("Error writing log file %v: %v", logPath, err)
}
log.Println("Log written")
return nil
}
func AppendLog(job types.Job, entries []LogEntry) error {
lock, err := Lock(job.GetJobBaseFileName(), "LOG")
if err != nil {
return err
}
defer func() {
Unlock(lock)
}()
logDir, err := getLibDir("states")
if err != nil {
return err
}
var logPath = filepath.FromSlash(fmt.Sprintf("%v/%v.log.json", logDir, job.GetJobBaseFileName()))
logDb, err := LoadLog(logPath)
if err != nil {
return err
}
logDb.JobFullName = job.GetJobBaseFileName()
var maxId int = 1
if len(logDb.Entries) > 0 {
maxId = logDb.Entries[len(logDb.Entries)-1].Id
}
for _, e := range entries {
maxId++
e.Id = maxId
logDb.Entries = append(logDb.Entries, e)
}
for len(logDb.Entries) > MAX_LOG_ENTRIES {
logDb.Entries = logDb.Entries[:1]
}
return logDb.Save(logPath)
}
func ShowAllLogs() {
dirs := findAllStateDirs()
var remote = os.Getenv("REMOTE")
if remote == "" {
remote = "-no-remote-"
}
for _, d := range dirs {
fsi, err := ioutil.ReadDir(d.Path)
log.Printf("Scanning path %v", d.Path)
if err != nil {
continue
}
for _, e := range fsi {
if strings.LastIndex(e.Name(), ".log.json") < 0 {
continue
}
p := filepath.FromSlash(d.Path + "/" + e.Name())
jfn := strings.Replace(e.Name(), ".log.json", "", -1)
lock, err := Lock(jfn, "LOG")
if err != nil {
log.Printf("Can't lock log %v: %v, skipping!", p, err)
continue
}
defer func() {
Unlock(lock)
}()
log.Printf("Processing log file %v", p)
logDb, err := LoadLog(p)
if err != nil {
log.Printf("Can't read log %v: %v, skipping!", p, err)
continue
}
var maxSent = logDb.MaxSentByRemote[remote]
fmt.Printf("[[[JobWatch %v/%v]]]\n", d.UserId, logDb.JobFullName)
var sentRem = MAX_LOG_SEND
for _, l := range logDb.Entries {
if l.Id <= maxSent {
continue
}
fmt.Printf("%v %v: %v\n", l.State, l.Date, l.Text)
maxSent = l.Id
sentRem--
if sentRem <= 0 {
break
}
}
if logDb.MaxSentByRemote == nil {
logDb.MaxSentByRemote = map[string]int{}
}
logDb.MaxSentByRemote[remote] = maxSent
logDb.Save(p)
}
}
}
func ToLogState(s types.CMKState) LogEntryState {
var p = LOG_UNKWN
switch s {
case types.OK:
p = LOG_OK
case types.WARN:
p = LOG_WARN
case types.CRIT:
p = LOG_CRIT
}
return p
}