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"
|
"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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
17
log/level.go
17
log/level.go
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
@ -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]"
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue