128 lines
3.2 KiB
Go
128 lines
3.2 KiB
Go
package database
|
|
|
|
import (
|
|
"regexp"
|
|
"time"
|
|
|
|
"dev.sum7.eu/genofire/golang-lib/file"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const AlertMsg = "alert service from logmania, device did not send new message for a while"
|
|
|
|
type DB struct {
|
|
Hostname map[string]string `json:"hostname"`
|
|
HostTo map[string]map[string]bool `json:"host_to"`
|
|
MaxPrioIn map[string]log.Level `json:"maxLevel"`
|
|
RegexIn map[string]map[string]*regexp.Regexp `json:"regexIn"`
|
|
Lastseen map[string]time.Time `json:"lastseen,omitempty"`
|
|
LastseenNotify map[string]time.Time `json:"-"`
|
|
}
|
|
|
|
func (db *DB) SendTo(e *log.Entry) (*log.Entry, []string) {
|
|
hostname, ok := e.Data["hostname"].(string)
|
|
if !ok {
|
|
return e, nil
|
|
}
|
|
if to, ok := db.HostTo[hostname]; ok {
|
|
if e.Message != AlertMsg && hostname != "" {
|
|
db.Lastseen[hostname] = time.Now()
|
|
}
|
|
var toList []string
|
|
for toEntry, _ := range to {
|
|
if lvl := db.MaxPrioIn[toEntry]; e.Level >= lvl {
|
|
continue
|
|
}
|
|
if regex, ok := db.RegexIn[toEntry]; ok {
|
|
stopForTo := false
|
|
for _, expr := range regex {
|
|
if expr.MatchString(e.Message) {
|
|
stopForTo = true
|
|
continue
|
|
}
|
|
}
|
|
if stopForTo {
|
|
continue
|
|
}
|
|
}
|
|
toList = append(toList, toEntry)
|
|
}
|
|
if replaceHostname, ok := db.Hostname[hostname]; ok {
|
|
entry := e.WithField("hostname", replaceHostname)
|
|
entry.Level = e.Level
|
|
entry.Message = e.Message
|
|
return entry, toList
|
|
}
|
|
return e, toList
|
|
} else {
|
|
db.HostTo[hostname] = make(map[string]bool)
|
|
}
|
|
return e, nil
|
|
}
|
|
|
|
func (db *DB) AddRegex(to, expression string) error {
|
|
regex, err := regexp.Compile(expression)
|
|
if err == nil {
|
|
if _, ok := db.RegexIn[to]; !ok {
|
|
db.RegexIn[to] = make(map[string]*regexp.Regexp)
|
|
}
|
|
db.RegexIn[to][expression] = regex
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
func ReadDBFile(path string) *DB {
|
|
var db DB
|
|
|
|
if err := file.ReadJSON(path, &db); err == nil {
|
|
log.Infof("loaded %d hosts", len(db.HostTo))
|
|
if db.Lastseen == nil {
|
|
db.Lastseen = make(map[string]time.Time)
|
|
}
|
|
if db.LastseenNotify == nil {
|
|
db.LastseenNotify = make(map[string]time.Time)
|
|
}
|
|
if db.RegexIn == nil {
|
|
db.RegexIn = make(map[string]map[string]*regexp.Regexp)
|
|
} else {
|
|
for to, regexs := range db.RegexIn {
|
|
for exp, _ := range regexs {
|
|
db.AddRegex(to, exp)
|
|
}
|
|
}
|
|
}
|
|
return &db
|
|
} else {
|
|
log.Error("failed to open db file: ", path, ":", err)
|
|
}
|
|
return &DB{
|
|
Hostname: make(map[string]string),
|
|
HostTo: make(map[string]map[string]bool),
|
|
MaxPrioIn: make(map[string]log.Level),
|
|
RegexIn: make(map[string]map[string]*regexp.Regexp),
|
|
Lastseen: make(map[string]time.Time),
|
|
LastseenNotify: make(map[string]time.Time),
|
|
}
|
|
}
|
|
|
|
func (db *DB) Alert(expired time.Duration, send func(e *log.Entry) error) {
|
|
c := time.Tick(time.Minute)
|
|
|
|
for range c {
|
|
now := time.Now()
|
|
for host, time := range db.Lastseen {
|
|
if time.Before(now.Add(expired * -2)) {
|
|
if timeNotify, ok := db.LastseenNotify[host]; !ok || !time.Before(timeNotify) {
|
|
db.LastseenNotify[host] = now
|
|
entry := log.NewEntry(log.New())
|
|
entry.Level = log.ErrorLevel
|
|
entry.Message = AlertMsg
|
|
entry.WithField("hostname", host)
|
|
send(entry)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|