add bot + add detect of timestemp in syslog

This commit is contained in:
Martin Geno 2017-08-11 17:45:42 +02:00
parent b38f97d97d
commit e25a322943
No known key found for this signature in database
GPG Key ID: F0D39A37E925E941
11 changed files with 261 additions and 37 deletions

72
bot/command.go Normal file
View File

@ -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()))
}

41
bot/main.go Normal file
View File

@ -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))
}
}

View File

@ -15,10 +15,12 @@ import (
"os/signal" "os/signal"
"syscall" "syscall"
"github.com/genofire/logmania/bot"
"github.com/genofire/logmania/lib" "github.com/genofire/logmania/lib"
log "github.com/genofire/logmania/log" log "github.com/genofire/logmania/log"
"github.com/genofire/logmania/notify" "github.com/genofire/logmania/notify"
allNotify "github.com/genofire/logmania/notify/all" allNotify "github.com/genofire/logmania/notify/all"
configNotify "github.com/genofire/logmania/notify/config"
"github.com/genofire/logmania/receive" "github.com/genofire/logmania/receive"
allReceiver "github.com/genofire/logmania/receive/all" allReceiver "github.com/genofire/logmania/receive/all"
) )
@ -26,10 +28,11 @@ import (
var ( var (
configPath string configPath string
config *lib.Config config *lib.Config
notifyConfig *notify.NotifyState notifyState *configNotify.NotifyState
notifier notify.Notifier notifier notify.Notifier
receiver receive.Receiver receiver receive.Receiver
logChannel chan *log.Entry logChannel chan *log.Entry
logmaniaBot *bot.Bot
) )
func main() { func main() {
@ -41,10 +44,12 @@ func main() {
log.Panicf("Could not load '%s' for configuration.", configPath) log.Panicf("Could not load '%s' for configuration.", configPath)
} }
notifyConfig := notify.ReadStateFile(config.Notify.StateFile) notifyState := configNotify.ReadStateFile(config.Notify.StateFile)
go notifyConfig.Saver(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 log.Save = notifier.Send
logChannel = make(chan *log.Entry) logChannel = make(chan *log.Entry)
@ -97,5 +102,5 @@ func reload() {
go receiver.Listen() go receiver.Listen()
notifier.Close() notifier.Close()
notifier = allNotify.Init(&config.Notify, notifyConfig) notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
} }

View File

@ -1 +1,77 @@
package syslog 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)
}

View File

@ -30,6 +30,23 @@ func (l LogLevel) String() string {
return "NOT VALID" 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 * log command
*/ */

View File

@ -1,9 +1,11 @@
package all package all
import ( import (
"github.com/genofire/logmania/bot"
"github.com/genofire/logmania/lib" "github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log" "github.com/genofire/logmania/log"
"github.com/genofire/logmania/notify" "github.com/genofire/logmania/notify"
configNotify "github.com/genofire/logmania/notify/config"
) )
type Notifier struct { type Notifier struct {
@ -12,10 +14,10 @@ type Notifier struct {
channelNotify chan *log.Entry 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 var list []notify.Notifier
for _, init := range notify.NotifyRegister { for _, init := range notify.NotifyRegister {
notify := init(config, state) notify := init(config, state, bot)
if notify == nil { if notify == nil {
continue continue

View File

@ -1,4 +1,4 @@
package notify package config
import ( import (
"encoding/json" "encoding/json"
@ -21,7 +21,7 @@ func (state *NotifyState) SendTo(e *log.Entry) []string {
if to, ok := state.HostTo[e.Hostname]; ok { if to, ok := state.HostTo[e.Hostname]; ok {
var toList []string var toList []string
for _, toEntry := range to { for _, toEntry := range to {
if lvl := state.MaxPrioIn[toEntry]; e.Level > lvl { if lvl := state.MaxPrioIn[toEntry]; e.Level < lvl {
continue continue
} }
toList = append(toList, toEntry) toList = append(toList, toEntry)

View File

@ -8,9 +8,11 @@ import (
"github.com/bclicn/color" "github.com/bclicn/color"
"github.com/genofire/logmania/bot"
"github.com/genofire/logmania/lib" "github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log" "github.com/genofire/logmania/log"
"github.com/genofire/logmania/notify" "github.com/genofire/logmania/notify"
configNotify "github.com/genofire/logmania/notify/config"
) )
var ( var (
@ -25,7 +27,7 @@ type Notifier struct {
ShowTime bool 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{ return &Notifier{
TimeFormat: "2006-01-02 15:04:05", TimeFormat: "2006-01-02 15:04:05",
ShowTime: true, 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) // handle a log entry (print it on the terminal with color)
func (n *Notifier) Send(e *log.Entry) { func (n *Notifier) Send(e *log.Entry) {
if e.Hostname != "" {
return
}
v := []interface{}{} v := []interface{}{}
format := "[%s]" format := "[%s]"

View File

@ -1,8 +1,10 @@
package notify package notify
import ( import (
"github.com/genofire/logmania/bot"
"github.com/genofire/logmania/lib" "github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log" "github.com/genofire/logmania/log"
configNotify "github.com/genofire/logmania/notify/config"
) )
var NotifyRegister []NotifyInit var NotifyRegister []NotifyInit
@ -12,7 +14,7 @@ type Notifier interface {
Close() Close()
} }
type NotifyInit func(*lib.NotifyConfig, *NotifyState) Notifier type NotifyInit func(*lib.NotifyConfig, *configNotify.NotifyState, *bot.Bot) Notifier
func AddNotifier(n NotifyInit) { func AddNotifier(n NotifyInit) {
NotifyRegister = append(NotifyRegister, n) NotifyRegister = append(NotifyRegister, n)

View File

@ -1,19 +1,22 @@
package xmpp package xmpp
import ( import (
xmpp "github.com/mattn/go-xmpp"
"github.com/genofire/logmania/bot"
"github.com/genofire/logmania/lib" "github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log" "github.com/genofire/logmania/log"
"github.com/genofire/logmania/notify" "github.com/genofire/logmania/notify"
xmpp "github.com/mattn/go-xmpp" configNotify "github.com/genofire/logmania/notify/config"
) )
type Notifier struct { type Notifier struct {
notify.Notifier notify.Notifier
client *xmpp.Client 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{ options := xmpp.Options{
Host: config.XMPP.Host, Host: config.XMPP.Host,
User: config.XMPP.Username, User: config.XMPP.Username,
@ -28,6 +31,21 @@ func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
if err != nil { if err != nil {
return 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} return &Notifier{client: client, state: state}
} }

View File

@ -1,9 +1,7 @@
package syslog package syslog
import ( import (
"regexp" libSyslog "github.com/genofire/logmania/lib/syslog"
"strconv"
"github.com/genofire/logmania/log" "github.com/genofire/logmania/log"
) )
@ -19,23 +17,11 @@ var SyslogPriorityMap = map[int]log.LogLevel{
} }
func toLogEntry(msg []byte, from string) *log.Entry { func toLogEntry(msg []byte, from string) *log.Entry {
re := regexp.MustCompile("<([0-9]*)>(.*)") syslogMsg := libSyslog.Parse(msg)
match := re.FindStringSubmatch(string(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{ return &log.Entry{
Level: SyslogPriorityMap[prio], Level: SyslogPriorityMap[syslogMsg.Severity],
Text: text, Text: syslogMsg.Content,
Hostname: from, Hostname: from,
} }
} }