add bot + add detect of timestemp in syslog
This commit is contained in:
parent
b38f97d97d
commit
e25a322943
|
@ -0,0 +1,72 @@
|
|||
package bot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/genofire/logmania/log"
|
||||
)
|
||||
|
||||
type commandFunc func(func(string), string, []string)
|
||||
|
||||
func (b *Bot) help(answer func(string), from string, params []string) {
|
||||
msg := fmt.Sprintf("Hi %s there are the following commands:\n", from)
|
||||
for cmd := range b.commands {
|
||||
msg = fmt.Sprintf("%s - !%s\n", msg, cmd)
|
||||
}
|
||||
answer(msg)
|
||||
}
|
||||
|
||||
func (b *Bot) sendTo(answer func(string), from string, params []string) {
|
||||
host := params[0]
|
||||
to := from
|
||||
if len(params) > 1 {
|
||||
to = params[1]
|
||||
}
|
||||
|
||||
if list, ok := b.state.HostTo[host]; ok {
|
||||
b.state.HostTo[host] = append(list, to)
|
||||
} else {
|
||||
b.state.HostTo[host] = []string{to}
|
||||
}
|
||||
|
||||
answer(fmt.Sprintf("added %s in list of %s", to, from))
|
||||
}
|
||||
|
||||
func (b *Bot) setHostname(answer func(string), from string, params []string) {
|
||||
host := params[0]
|
||||
name := params[1]
|
||||
|
||||
b.state.Hostname[host] = name
|
||||
|
||||
answer(fmt.Sprintf("set for %s the hostname %s", host, name))
|
||||
}
|
||||
|
||||
func (b *Bot) listHostname(answer func(string), from string, params []string) {
|
||||
msg := "hostnames:\n"
|
||||
for ip, hostname := range b.state.Hostname {
|
||||
msg = fmt.Sprintf("%s%s - %s", msg, ip, hostname)
|
||||
}
|
||||
answer(msg)
|
||||
}
|
||||
|
||||
func (b *Bot) listMaxfilter(answer func(string), from string, params []string) {
|
||||
msg := "filters:\n"
|
||||
for to, filter := range b.state.MaxPrioIn {
|
||||
msg = fmt.Sprintf("%s%s - %s", msg, to, filter.String())
|
||||
}
|
||||
answer(msg)
|
||||
}
|
||||
|
||||
func (b *Bot) setMaxfilter(answer func(string), from string, params []string) {
|
||||
to := from
|
||||
max := log.NewLoglevel(params[0])
|
||||
|
||||
if len(params) > 1 {
|
||||
to = params[0]
|
||||
max = log.NewLoglevel(params[1])
|
||||
}
|
||||
|
||||
b.state.MaxPrioIn[to] = max
|
||||
|
||||
answer(fmt.Sprintf("set filter for %s to %s", to, max.String()))
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package bot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
)
|
||||
|
||||
type Bot struct {
|
||||
state *configNotify.NotifyState
|
||||
commands map[string]commandFunc
|
||||
}
|
||||
|
||||
func NewBot(state *configNotify.NotifyState) *Bot {
|
||||
b := &Bot{
|
||||
state: state,
|
||||
}
|
||||
b.commands = map[string]commandFunc{
|
||||
"help": b.help,
|
||||
"send-to": b.sendTo,
|
||||
"hostname-set": b.setHostname,
|
||||
"hostname-list": b.listHostname,
|
||||
"filter-set": b.setMaxfilter,
|
||||
"filter-list": b.listMaxfilter,
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bot) Handle(answer func(string), from, msg string) {
|
||||
msgParts := strings.Split(msg, " ")
|
||||
if msgParts[0][0] != '!' {
|
||||
return
|
||||
}
|
||||
cmdName := msgParts[0][1:]
|
||||
if cmd, ok := b.commands[cmdName]; ok {
|
||||
cmd(answer, from, msgParts[1:])
|
||||
} else {
|
||||
answer(fmt.Sprintf("not found command: !%s", cmdName))
|
||||
}
|
||||
}
|
|
@ -15,10 +15,12 @@ import (
|
|||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/lib"
|
||||
log "github.com/genofire/logmania/log"
|
||||
"github.com/genofire/logmania/notify"
|
||||
allNotify "github.com/genofire/logmania/notify/all"
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
"github.com/genofire/logmania/receive"
|
||||
allReceiver "github.com/genofire/logmania/receive/all"
|
||||
)
|
||||
|
@ -26,10 +28,11 @@ import (
|
|||
var (
|
||||
configPath string
|
||||
config *lib.Config
|
||||
notifyConfig *notify.NotifyState
|
||||
notifyState *configNotify.NotifyState
|
||||
notifier notify.Notifier
|
||||
receiver receive.Receiver
|
||||
logChannel chan *log.Entry
|
||||
logmaniaBot *bot.Bot
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -41,10 +44,12 @@ func main() {
|
|||
log.Panicf("Could not load '%s' for configuration.", configPath)
|
||||
}
|
||||
|
||||
notifyConfig := notify.ReadStateFile(config.Notify.StateFile)
|
||||
go notifyConfig.Saver(config.Notify.StateFile)
|
||||
notifyState := configNotify.ReadStateFile(config.Notify.StateFile)
|
||||
go notifyState.Saver(config.Notify.StateFile)
|
||||
|
||||
notifier = allNotify.Init(&config.Notify, notifyConfig)
|
||||
logmaniaBot = bot.NewBot(notifyState)
|
||||
|
||||
notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
|
||||
log.Save = notifier.Send
|
||||
logChannel = make(chan *log.Entry)
|
||||
|
||||
|
@ -97,5 +102,5 @@ func reload() {
|
|||
go receiver.Listen()
|
||||
|
||||
notifier.Close()
|
||||
notifier = allNotify.Init(&config.Notify, notifyConfig)
|
||||
notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
|
||||
}
|
||||
|
|
|
@ -1 +1,77 @@
|
|||
package syslog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SyslogMessage struct {
|
||||
Timestemp time.Time
|
||||
Hostname string
|
||||
Tag string
|
||||
Service int
|
||||
Content string
|
||||
Facility int
|
||||
Severity int
|
||||
}
|
||||
|
||||
func Parse(binaryMsg []byte) *SyslogMessage {
|
||||
var err error
|
||||
|
||||
msg := &SyslogMessage{}
|
||||
|
||||
re := regexp.MustCompile("<([0-9]*)>(.*)")
|
||||
match := re.FindStringSubmatch(string(binaryMsg))
|
||||
|
||||
prio, _ := strconv.Atoi(match[1])
|
||||
msg.Facility = prio / 8
|
||||
msg.Severity = prio % 8
|
||||
|
||||
timeLength := len(time.RFC3339)
|
||||
if len(match[2]) > timeLength {
|
||||
msg.Timestemp, err = time.Parse(time.RFC3339, match[2][:timeLength])
|
||||
if err != nil {
|
||||
timeLength = 0
|
||||
}
|
||||
}
|
||||
timeLength = len(msg.Timestemp.Format(time.Stamp))
|
||||
if len(match[2]) > timeLength {
|
||||
msg.Timestemp, err = time.Parse(time.Stamp, match[2][:timeLength])
|
||||
if err != nil {
|
||||
timeLength = 0
|
||||
}
|
||||
}
|
||||
|
||||
msg.Content = match[2][timeLength:]
|
||||
|
||||
/*
|
||||
TODO: detect other parts in content
|
||||
- Hostname (if exists)
|
||||
- Tag
|
||||
- Service
|
||||
*/
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
func (msg *SyslogMessage) Priority() int {
|
||||
return msg.Facility*8 + msg.Severity
|
||||
}
|
||||
|
||||
func (msg *SyslogMessage) Dump() []byte {
|
||||
result := fmt.Sprintf("<%d>%s %s %s[%d]: %s",
|
||||
msg.Priority(),
|
||||
msg.Timestemp.Format(time.RFC3339),
|
||||
msg.Hostname,
|
||||
msg.Tag,
|
||||
msg.Service,
|
||||
msg.Content,
|
||||
)
|
||||
if !strings.HasSuffix(msg.Content, "\n") {
|
||||
result = fmt.Sprintf("%s\n", result)
|
||||
}
|
||||
return []byte(result)
|
||||
}
|
||||
|
|
17
log/level.go
17
log/level.go
|
@ -30,6 +30,23 @@ func (l LogLevel) String() string {
|
|||
return "NOT VALID"
|
||||
}
|
||||
|
||||
func NewLoglevel(by string) LogLevel {
|
||||
switch by {
|
||||
case "debug":
|
||||
return DebugLevel
|
||||
case "info":
|
||||
return InfoLevel
|
||||
case "warn":
|
||||
return WarnLevel
|
||||
case "error":
|
||||
return ErrorLevel
|
||||
case "panic":
|
||||
return PanicLevel
|
||||
|
||||
}
|
||||
return DebugLevel
|
||||
}
|
||||
|
||||
/**
|
||||
* log command
|
||||
*/
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package all
|
||||
|
||||
import (
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/lib"
|
||||
"github.com/genofire/logmania/log"
|
||||
"github.com/genofire/logmania/notify"
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
)
|
||||
|
||||
type Notifier struct {
|
||||
|
@ -12,10 +14,10 @@ type Notifier struct {
|
|||
channelNotify chan *log.Entry
|
||||
}
|
||||
|
||||
func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
|
||||
func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bot) notify.Notifier {
|
||||
var list []notify.Notifier
|
||||
for _, init := range notify.NotifyRegister {
|
||||
notify := init(config, state)
|
||||
notify := init(config, state, bot)
|
||||
|
||||
if notify == nil {
|
||||
continue
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package notify
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -21,7 +21,7 @@ func (state *NotifyState) SendTo(e *log.Entry) []string {
|
|||
if to, ok := state.HostTo[e.Hostname]; ok {
|
||||
var toList []string
|
||||
for _, toEntry := range to {
|
||||
if lvl := state.MaxPrioIn[toEntry]; e.Level > lvl {
|
||||
if lvl := state.MaxPrioIn[toEntry]; e.Level < lvl {
|
||||
continue
|
||||
}
|
||||
toList = append(toList, toEntry)
|
|
@ -8,9 +8,11 @@ import (
|
|||
|
||||
"github.com/bclicn/color"
|
||||
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/lib"
|
||||
"github.com/genofire/logmania/log"
|
||||
"github.com/genofire/logmania/notify"
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -25,7 +27,7 @@ type Notifier struct {
|
|||
ShowTime bool
|
||||
}
|
||||
|
||||
func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
|
||||
func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bot) notify.Notifier {
|
||||
return &Notifier{
|
||||
TimeFormat: "2006-01-02 15:04:05",
|
||||
ShowTime: true,
|
||||
|
@ -34,6 +36,9 @@ func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
|
|||
|
||||
// handle a log entry (print it on the terminal with color)
|
||||
func (n *Notifier) Send(e *log.Entry) {
|
||||
if e.Hostname != "" {
|
||||
return
|
||||
}
|
||||
v := []interface{}{}
|
||||
format := "[%s]"
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package notify
|
||||
|
||||
import (
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/lib"
|
||||
"github.com/genofire/logmania/log"
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
)
|
||||
|
||||
var NotifyRegister []NotifyInit
|
||||
|
@ -12,7 +14,7 @@ type Notifier interface {
|
|||
Close()
|
||||
}
|
||||
|
||||
type NotifyInit func(*lib.NotifyConfig, *NotifyState) Notifier
|
||||
type NotifyInit func(*lib.NotifyConfig, *configNotify.NotifyState, *bot.Bot) Notifier
|
||||
|
||||
func AddNotifier(n NotifyInit) {
|
||||
NotifyRegister = append(NotifyRegister, n)
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
package xmpp
|
||||
|
||||
import (
|
||||
xmpp "github.com/mattn/go-xmpp"
|
||||
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/lib"
|
||||
"github.com/genofire/logmania/log"
|
||||
"github.com/genofire/logmania/notify"
|
||||
xmpp "github.com/mattn/go-xmpp"
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
)
|
||||
|
||||
type Notifier struct {
|
||||
notify.Notifier
|
||||
client *xmpp.Client
|
||||
state *notify.NotifyState
|
||||
state *configNotify.NotifyState
|
||||
}
|
||||
|
||||
func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
|
||||
func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bot) notify.Notifier {
|
||||
options := xmpp.Options{
|
||||
Host: config.XMPP.Host,
|
||||
User: config.XMPP.Username,
|
||||
|
@ -28,6 +31,21 @@ func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
|
|||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
chat, err := client.Recv()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
switch v := chat.(type) {
|
||||
case xmpp.Chat:
|
||||
bot.Handle(func(answer string) {
|
||||
client.SendHtml(xmpp.Chat{Remote: v.Remote, Type: "chat", Text: answer})
|
||||
}, v.Remote, v.Text)
|
||||
}
|
||||
}
|
||||
}()
|
||||
log.Info("xmpp startup")
|
||||
return &Notifier{client: client, state: state}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package syslog
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
libSyslog "github.com/genofire/logmania/lib/syslog"
|
||||
"github.com/genofire/logmania/log"
|
||||
)
|
||||
|
||||
|
@ -19,23 +17,11 @@ var SyslogPriorityMap = map[int]log.LogLevel{
|
|||
}
|
||||
|
||||
func toLogEntry(msg []byte, from string) *log.Entry {
|
||||
re := regexp.MustCompile("<([0-9]*)>(.*)")
|
||||
match := re.FindStringSubmatch(string(msg))
|
||||
syslogMsg := libSyslog.Parse(msg)
|
||||
|
||||
if len(match) <= 1 {
|
||||
return &log.Entry{
|
||||
Level: log.DebugLevel,
|
||||
Text: string(msg),
|
||||
Hostname: from,
|
||||
}
|
||||
}
|
||||
v, _ := strconv.Atoi(match[1])
|
||||
prio := v % 8
|
||||
text := match[2]
|
||||
|
||||
return &log.Entry{
|
||||
Level: SyslogPriorityMap[prio],
|
||||
Text: text,
|
||||
Level: SyslogPriorityMap[syslogMsg.Severity],
|
||||
Text: syslogMsg.Content,
|
||||
Hostname: from,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue