189 lines
3.7 KiB
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
|
|
}
|