[TASK] extract database, xmpp reconnect & websocket/logrus server (client WIP)
This commit is contained in:
parent
c46cea3c7a
commit
a96efdf3cc
|
@ -27,6 +27,7 @@ done
|
|||
# Failures have incomplete results, so don't send
|
||||
if [ "$FAIL" -eq 0 ]; then
|
||||
goveralls -v -coverprofile=profile.cov -service=$CI -repotoken=$COVERALLS_REPO_TOKEN
|
||||
bash <(curl -s https://codecov.io/bash) -t $CODECOV_TOKEN -f profile.cov
|
||||
fi
|
||||
|
||||
exit $FAIL
|
||||
|
|
|
@ -32,10 +32,10 @@ func (b *Bot) sendTo(answer func(string), from string, params []string) {
|
|||
to = params[1]
|
||||
}
|
||||
|
||||
if _, ok := b.state.HostTo[host]; !ok {
|
||||
b.state.HostTo[host] = make(map[string]bool)
|
||||
if _, ok := b.db.HostTo[host]; !ok {
|
||||
b.db.HostTo[host] = make(map[string]bool)
|
||||
}
|
||||
b.state.HostTo[host][to] = true
|
||||
b.db.HostTo[host][to] = true
|
||||
|
||||
answer(fmt.Sprintf("added %s in list of %s", to, host))
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ func (b *Bot) sendRemove(answer func(string), from string, params []string) {
|
|||
to = params[1]
|
||||
}
|
||||
|
||||
if list, ok := b.state.HostTo[host]; ok {
|
||||
if list, ok := b.db.HostTo[host]; ok {
|
||||
delete(list, to)
|
||||
b.state.HostTo[host] = list
|
||||
b.db.HostTo[host] = list
|
||||
answer(fmt.Sprintf("removed %s in list of %s", to, host))
|
||||
} else {
|
||||
answer("not found host")
|
||||
|
@ -74,7 +74,7 @@ func (b *Bot) sendList(answer func(string), from string, params []string) {
|
|||
of = params[0]
|
||||
}
|
||||
}
|
||||
for ip, toMap := range b.state.HostTo {
|
||||
for ip, toMap := range b.db.HostTo {
|
||||
toList := ""
|
||||
show := all
|
||||
for to := range toMap {
|
||||
|
@ -90,7 +90,7 @@ func (b *Bot) sendList(answer func(string), from string, params []string) {
|
|||
if len(toList) > 3 {
|
||||
toList = toList[3:]
|
||||
}
|
||||
if hostname, ok := b.state.Hostname[ip]; ok {
|
||||
if hostname, ok := b.db.Hostname[ip]; ok {
|
||||
msg = fmt.Sprintf("%s%s (%s): %s\n", msg, ip, hostname, toList)
|
||||
} else {
|
||||
msg = fmt.Sprintf("%s%s: %s\n", msg, ip, toList)
|
||||
|
@ -103,8 +103,8 @@ func (b *Bot) sendList(answer func(string), from string, params []string) {
|
|||
// list all host with his ip
|
||||
func (b *Bot) listHostname(answer func(string), from string, params []string) {
|
||||
msg := "hostnames:\n"
|
||||
for ip, hostname := range b.state.Hostname {
|
||||
if last, ok := b.state.Lastseen[ip]; ok {
|
||||
for ip, hostname := range b.db.Hostname {
|
||||
if last, ok := b.db.Lastseen[ip]; ok {
|
||||
got, _ := timeago.TimeAgoWithTime(time.Now(), last)
|
||||
msg = fmt.Sprintf("%s%s - %s (%s)\n", msg, ip, hostname, got)
|
||||
} else {
|
||||
|
@ -123,7 +123,7 @@ func (b *Bot) setHostname(answer func(string), from string, params []string) {
|
|||
host := params[0]
|
||||
name := params[1]
|
||||
|
||||
b.state.Hostname[host] = name
|
||||
b.db.Hostname[host] = name
|
||||
|
||||
answer(fmt.Sprintf("set for %s the hostname %s", host, name))
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ func (b *Bot) listMaxfilter(answer func(string), from string, params []string) {
|
|||
msg := "filters: "
|
||||
if len(params) > 0 && params[0] == "all" {
|
||||
msg = fmt.Sprintf("%s\n", msg)
|
||||
for to, filter := range b.state.MaxPrioIn {
|
||||
for to, filter := range b.db.MaxPrioIn {
|
||||
msg = fmt.Sprintf("%s%s - %s\n", msg, to, filter.String())
|
||||
}
|
||||
} else {
|
||||
|
@ -141,7 +141,7 @@ func (b *Bot) listMaxfilter(answer func(string), from string, params []string) {
|
|||
if len(params) > 0 {
|
||||
of = params[0]
|
||||
}
|
||||
if filter, ok := b.state.MaxPrioIn[of]; ok {
|
||||
if filter, ok := b.db.MaxPrioIn[of]; ok {
|
||||
msg = fmt.Sprintf("%s of %s is %s", msg, of, filter)
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ func (b *Bot) setMaxfilter(answer func(string), from string, params []string) {
|
|||
return
|
||||
}
|
||||
|
||||
b.state.MaxPrioIn[to] = max
|
||||
b.db.MaxPrioIn[to] = max
|
||||
|
||||
answer(fmt.Sprintf("set filter for %s to %s", to, max.String()))
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ func (b *Bot) setMaxfilter(answer func(string), from string, params []string) {
|
|||
func (b *Bot) listRegex(answer func(string), from string, params []string) {
|
||||
msg := "regexs:\n"
|
||||
if len(params) > 0 && params[0] == "all" {
|
||||
for to, regexs := range b.state.RegexIn {
|
||||
for to, regexs := range b.db.RegexIn {
|
||||
msg = fmt.Sprintf("%s%s\n-------------\n", msg, to)
|
||||
for expression := range regexs {
|
||||
msg = fmt.Sprintf("%s - %s\n", msg, expression)
|
||||
|
@ -189,7 +189,7 @@ func (b *Bot) listRegex(answer func(string), from string, params []string) {
|
|||
if len(params) > 0 {
|
||||
of = params[0]
|
||||
}
|
||||
if regexs, ok := b.state.RegexIn[of]; ok {
|
||||
if regexs, ok := b.db.RegexIn[of]; ok {
|
||||
msg = fmt.Sprintf("%s%s\n-------------\n", msg, from)
|
||||
for expression := range regexs {
|
||||
msg = fmt.Sprintf("%s - %s\n", msg, expression)
|
||||
|
@ -207,7 +207,7 @@ func (b *Bot) addRegex(answer func(string), from string, params []string) {
|
|||
}
|
||||
regex := strings.Join(params, " ")
|
||||
|
||||
if err := b.state.AddRegex(from, regex); err == nil {
|
||||
if err := b.db.AddRegex(from, regex); err == nil {
|
||||
answer(fmt.Sprintf("add regex for \"%s\" to %s", from, regex))
|
||||
} else {
|
||||
answer(fmt.Sprintf("\"%s\" is no valid regex expression: %s", regex, err))
|
||||
|
@ -221,6 +221,6 @@ func (b *Bot) delRegex(answer func(string), from string, params []string) {
|
|||
return
|
||||
}
|
||||
regex := strings.Join(params, " ")
|
||||
delete(b.state.RegexIn[from], regex)
|
||||
delete(b.db.RegexIn[from], regex)
|
||||
b.listRegex(answer, from, []string{})
|
||||
}
|
||||
|
|
|
@ -4,17 +4,17 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
"github.com/genofire/logmania/database"
|
||||
)
|
||||
|
||||
type Bot struct {
|
||||
state *configNotify.NotifyState
|
||||
db *database.DB
|
||||
commands map[string]commandFunc
|
||||
}
|
||||
|
||||
func NewBot(state *configNotify.NotifyState) *Bot {
|
||||
func NewBot(db *database.DB) *Bot {
|
||||
b := &Bot{
|
||||
state: state,
|
||||
db: db,
|
||||
}
|
||||
b.commands = map[string]commandFunc{
|
||||
"help": b.help,
|
||||
|
|
91
circle.yml
91
circle.yml
|
@ -1,36 +1,55 @@
|
|||
machine:
|
||||
environment:
|
||||
GOROOT: ""
|
||||
PATH: "/usr/local/go/bin:/usr/local/go_workspace/bin:~/.go_workspace/bin:${PATH}"
|
||||
GOPATH: "${HOME}/.go_workspace"
|
||||
|
||||
dependencies:
|
||||
override:
|
||||
- mkdir -p ~/.go_workspace/src/github.com/${CIRCLE_PROJECT_USERNAME}
|
||||
- ln -s ${HOME}/${CIRCLE_PROJECT_REPONAME} ${HOME}/.go_workspace/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
|
||||
- go get -t -d -v ./...
|
||||
- go install github.com/genofire/logmania
|
||||
post:
|
||||
- cp ~/.go_workspace/bin/logmania logmania.bin
|
||||
- tar -cvzf logmania-builded.tar.gz logmania.bin logmania_example.conf
|
||||
- mv logmania-builded.tar.gz $CIRCLE_ARTIFACTS
|
||||
|
||||
|
||||
|
||||
test:
|
||||
pre:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
override:
|
||||
- ./.test-coverage circle-ci
|
||||
|
||||
deployment:
|
||||
staging:
|
||||
branch: master
|
||||
commands:
|
||||
- ./deploy.sh $HOST_FOR_STAGING $PORT_FOR_STAGING
|
||||
|
||||
notify:
|
||||
webhooks:
|
||||
- url: https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN
|
||||
- url: https://hook2xmpp.pub.warehost.de/circleci
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/golang:latest
|
||||
working_directory: /go/src/github.com/genofire/logmania
|
||||
steps:
|
||||
- checkout
|
||||
- run: go get -t -d -v ./...
|
||||
- run: go install github.com/genofire/logmania
|
||||
- store_artifacts:
|
||||
path: /go/bin/
|
||||
destination: logmania
|
||||
test:
|
||||
docker:
|
||||
- image: circleci/golang:latest
|
||||
working_directory: /go/src/github.com/genofire/logmania
|
||||
steps:
|
||||
- checkout
|
||||
- run: go get -t -d -v ./...
|
||||
- run: go get github.com/mattn/goveralls
|
||||
- run: go get golang.org/x/tools/cmd/cover
|
||||
- run: ./.test-coverage circle-ci
|
||||
- store_test_results:
|
||||
path: ./
|
||||
destination: profile.cov
|
||||
test_race:
|
||||
docker:
|
||||
- image: circleci/golang:latest
|
||||
working_directory: /go/src/github.com/genofire/logmania
|
||||
steps:
|
||||
- checkout
|
||||
- run: go get -t -d -v ./...
|
||||
- run: go test -race ./...
|
||||
deploy:
|
||||
docker:
|
||||
- image: circleci/golang:latest
|
||||
working_directory: /go/src/github.com/genofire/logmania
|
||||
steps:
|
||||
- checkout
|
||||
- run: go get -t -d -v ./...
|
||||
- run: go install github.com/genofire/logmania
|
||||
- run: ./deploy.sh $HOST_FOR_STAGING $PORT_FOR_STAGING
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_tests:
|
||||
jobs:
|
||||
- build
|
||||
- test
|
||||
- test_race
|
||||
- deploy:
|
||||
requires:
|
||||
- build
|
||||
- test
|
||||
- test_race
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
@ -12,23 +13,23 @@ import (
|
|||
"github.com/genofire/golang-lib/file"
|
||||
"github.com/genofire/golang-lib/worker"
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/database"
|
||||
"github.com/genofire/logmania/lib"
|
||||
"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"
|
||||
)
|
||||
|
||||
var (
|
||||
configPath string
|
||||
config *lib.Config
|
||||
notifyState *configNotify.NotifyState
|
||||
stateSaveWorker *worker.Worker
|
||||
notifier notify.Notifier
|
||||
receiver receive.Receiver
|
||||
logChannel chan *log.Entry
|
||||
logmaniaBot *bot.Bot
|
||||
configPath string
|
||||
config *lib.Config
|
||||
db *database.DB
|
||||
dbSaveWorker *worker.Worker
|
||||
notifier notify.Notifier
|
||||
receiver receive.Receiver
|
||||
logChannel chan *log.Entry
|
||||
logmaniaBot *bot.Bot
|
||||
)
|
||||
|
||||
// serverCmd represents the serve command
|
||||
|
@ -46,23 +47,22 @@ var serverCmd = &cobra.Command{
|
|||
log.Panicf("Could not load '%s' for configuration.", configPath)
|
||||
}
|
||||
|
||||
notifyState = configNotify.ReadStateFile(config.Notify.StateFile)
|
||||
stateSaveWorker = file.NewSaveJSONWorker(time.Minute, config.Notify.StateFile, notifyState)
|
||||
db = database.ReadDBFile(config.DB)
|
||||
dbSaveWorker = file.NewSaveJSONWorker(time.Minute, config.DB, db)
|
||||
|
||||
logmaniaBot = bot.NewBot(notifyState)
|
||||
logmaniaBot = bot.NewBot(db)
|
||||
|
||||
notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
|
||||
log.AddHook(notifier)
|
||||
notifier = allNotify.Init(&config.Notify, db, logmaniaBot)
|
||||
logChannel = make(chan *log.Entry)
|
||||
|
||||
go func() {
|
||||
for a := range logChannel {
|
||||
notifier.Fire(a)
|
||||
notifier.Send(a)
|
||||
}
|
||||
}()
|
||||
|
||||
if config.Notify.AlertCheck.Duration > time.Duration(time.Second) {
|
||||
go notifyState.Alert(config.Notify.AlertCheck.Duration, notifier.Fire)
|
||||
go db.Alert(config.Notify.AlertCheck.Duration, notifier.Send)
|
||||
}
|
||||
|
||||
log.Info("starting logmania")
|
||||
|
@ -71,6 +71,16 @@ var serverCmd = &cobra.Command{
|
|||
|
||||
go receiver.Listen()
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: config.HTTPAddress,
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for system signal
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGUSR1)
|
||||
|
@ -91,8 +101,8 @@ var serverCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
func quit() {
|
||||
stateSaveWorker.Close()
|
||||
file.SaveJSON(config.Notify.StateFile, notifyState)
|
||||
dbSaveWorker.Close()
|
||||
file.SaveJSON(config.DB, db)
|
||||
receiver.Close()
|
||||
notifier.Close()
|
||||
log.Info("quit of logmania")
|
||||
|
@ -112,7 +122,7 @@ func reload() {
|
|||
go receiver.Listen()
|
||||
|
||||
notifier.Close()
|
||||
notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
|
||||
notifier = allNotify.Init(&config.Notify, db, logmaniaBot)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package config
|
||||
package database
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
const AlertMsg = "alert service from logmania, device did not send new message for a while"
|
||||
|
||||
type NotifyState struct {
|
||||
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"`
|
||||
|
@ -19,21 +19,21 @@ type NotifyState struct {
|
|||
LastseenNotify map[string]time.Time `json:"-"`
|
||||
}
|
||||
|
||||
func (state *NotifyState) SendTo(e *log.Entry) (*log.Entry, []string) {
|
||||
func (db *DB) SendTo(e *log.Entry) (*log.Entry, []string) {
|
||||
hostname, ok := e.Data["hostname"].(string)
|
||||
if !ok {
|
||||
return e, nil
|
||||
}
|
||||
if to, ok := state.HostTo[hostname]; ok {
|
||||
if to, ok := db.HostTo[hostname]; ok {
|
||||
if e.Message != AlertMsg && hostname != "" {
|
||||
state.Lastseen[hostname] = time.Now()
|
||||
db.Lastseen[hostname] = time.Now()
|
||||
}
|
||||
var toList []string
|
||||
for toEntry, _ := range to {
|
||||
if lvl := state.MaxPrioIn[toEntry]; e.Level >= lvl {
|
||||
if lvl := db.MaxPrioIn[toEntry]; e.Level >= lvl {
|
||||
continue
|
||||
}
|
||||
if regex, ok := state.RegexIn[toEntry]; ok {
|
||||
if regex, ok := db.RegexIn[toEntry]; ok {
|
||||
stopForTo := false
|
||||
for _, expr := range regex {
|
||||
if expr.MatchString(e.Message) {
|
||||
|
@ -47,7 +47,7 @@ func (state *NotifyState) SendTo(e *log.Entry) (*log.Entry, []string) {
|
|||
}
|
||||
toList = append(toList, toEntry)
|
||||
}
|
||||
if replaceHostname, ok := state.Hostname[hostname]; ok {
|
||||
if replaceHostname, ok := db.Hostname[hostname]; ok {
|
||||
entry := e.WithField("hostname", replaceHostname)
|
||||
entry.Level = e.Level
|
||||
entry.Message = e.Message
|
||||
|
@ -55,48 +55,48 @@ func (state *NotifyState) SendTo(e *log.Entry) (*log.Entry, []string) {
|
|||
}
|
||||
return e, toList
|
||||
} else {
|
||||
state.HostTo[hostname] = make(map[string]bool)
|
||||
db.HostTo[hostname] = make(map[string]bool)
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (state *NotifyState) AddRegex(to, expression string) error {
|
||||
func (db *DB) AddRegex(to, expression string) error {
|
||||
regex, err := regexp.Compile(expression)
|
||||
if err == nil {
|
||||
if _, ok := state.RegexIn[to]; !ok {
|
||||
state.RegexIn[to] = make(map[string]*regexp.Regexp)
|
||||
if _, ok := db.RegexIn[to]; !ok {
|
||||
db.RegexIn[to] = make(map[string]*regexp.Regexp)
|
||||
}
|
||||
state.RegexIn[to][expression] = regex
|
||||
db.RegexIn[to][expression] = regex
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ReadStateFile(path string) *NotifyState {
|
||||
var state NotifyState
|
||||
func ReadDBFile(path string) *DB {
|
||||
var db DB
|
||||
|
||||
if err := file.ReadJSON(path, &state); err == nil {
|
||||
log.Infof("loaded %d hosts", len(state.HostTo))
|
||||
if state.Lastseen == nil {
|
||||
state.Lastseen = make(map[string]time.Time)
|
||||
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 state.LastseenNotify == nil {
|
||||
state.LastseenNotify = make(map[string]time.Time)
|
||||
if db.LastseenNotify == nil {
|
||||
db.LastseenNotify = make(map[string]time.Time)
|
||||
}
|
||||
if state.RegexIn == nil {
|
||||
state.RegexIn = make(map[string]map[string]*regexp.Regexp)
|
||||
if db.RegexIn == nil {
|
||||
db.RegexIn = make(map[string]map[string]*regexp.Regexp)
|
||||
} else {
|
||||
for to, regexs := range state.RegexIn {
|
||||
for to, regexs := range db.RegexIn {
|
||||
for exp, _ := range regexs {
|
||||
state.AddRegex(to, exp)
|
||||
db.AddRegex(to, exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &state
|
||||
return &db
|
||||
} else {
|
||||
log.Error("failed to open state notify file: ", path, ":", err)
|
||||
log.Error("failed to open db file: ", path, ":", err)
|
||||
}
|
||||
return &NotifyState{
|
||||
return &DB{
|
||||
Hostname: make(map[string]string),
|
||||
HostTo: make(map[string]map[string]bool),
|
||||
MaxPrioIn: make(map[string]log.Level),
|
||||
|
@ -106,15 +106,15 @@ func ReadStateFile(path string) *NotifyState {
|
|||
}
|
||||
}
|
||||
|
||||
func (state *NotifyState) Alert(expired time.Duration, send func(e *log.Entry) error) {
|
||||
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 state.Lastseen {
|
||||
for host, time := range db.Lastseen {
|
||||
if time.Before(now.Add(expired * -2)) {
|
||||
if timeNotify, ok := state.LastseenNotify[host]; !ok || !time.Before(timeNotify) {
|
||||
state.LastseenNotify[host] = now
|
||||
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
|
|
@ -3,10 +3,10 @@ host=$1
|
|||
port=$2
|
||||
remote="circleci@${host}"
|
||||
echo "deploying..."
|
||||
ssh -p $port $remote sudo systemctl stop logmania;
|
||||
ssh -o StrictHostKeyChecking=no -p $port $remote sudo systemctl stop logmania;
|
||||
RETVAL=$?
|
||||
[ $RETVAL -ne 0 ] && exit 1
|
||||
scp -q -P $port ~/.go_workspace/bin/logmania $remote:~/bin/logmania;
|
||||
scp -q -P $port /go/bin/logmania $remote:~/bin/logmania;
|
||||
RETVAL=$?
|
||||
ssh -p $port $remote sudo systemctl start logmania;
|
||||
[ $RETVAL -eq 0 ] && RETVAL=$?
|
||||
|
|
|
@ -3,12 +3,13 @@ package lib
|
|||
// Struct of the configuration
|
||||
// e.g. under github.com/genofire/logmania/logmania_example.conf
|
||||
type Config struct {
|
||||
Notify NotifyConfig `toml:"notify"`
|
||||
Receive ReceiveConfig `toml:"receive"`
|
||||
Notify NotifyConfig `toml:"notify"`
|
||||
Receive ReceiveConfig `toml:"receive"`
|
||||
DB string `toml:"database"`
|
||||
HTTPAddress string `toml:"http_address"`
|
||||
}
|
||||
|
||||
type NotifyConfig struct {
|
||||
StateFile string `toml:"state_file"`
|
||||
AlertCheck Duration `toml:"alert_check"`
|
||||
Console bool `toml:"debug"`
|
||||
XMPP struct {
|
||||
|
@ -22,8 +23,6 @@ type NotifyConfig struct {
|
|||
StatusMessage string `toml:"status_message"`
|
||||
StartupNotify string `toml:"startup_notify"`
|
||||
} `toml:"xmpp"`
|
||||
IRC struct {
|
||||
} `toml:"irc"`
|
||||
}
|
||||
|
||||
type ReceiveConfig struct {
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/database"
|
||||
"github.com/genofire/logmania/lib"
|
||||
"github.com/genofire/logmania/notify"
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
)
|
||||
|
||||
type Notifier struct {
|
||||
|
@ -15,10 +15,10 @@ type Notifier struct {
|
|||
channelNotify chan *log.Entry
|
||||
}
|
||||
|
||||
func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bot) notify.Notifier {
|
||||
func Init(config *lib.NotifyConfig, db *database.DB, bot *bot.Bot) notify.Notifier {
|
||||
var list []notify.Notifier
|
||||
for _, init := range notify.NotifyRegister {
|
||||
notify := init(config, state, bot)
|
||||
notify := init(config, db, bot)
|
||||
|
||||
if notify == nil {
|
||||
continue
|
||||
|
@ -37,12 +37,12 @@ func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bo
|
|||
func (n *Notifier) sender() {
|
||||
for c := range n.channelNotify {
|
||||
for _, item := range n.list {
|
||||
item.Fire(c)
|
||||
item.Send(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) Fire(e *log.Entry) error {
|
||||
func (n *Notifier) Send(e *log.Entry) error {
|
||||
n.channelNotify <- e
|
||||
return nil
|
||||
}
|
||||
|
@ -52,14 +52,3 @@ func (n *Notifier) Close() {
|
|||
item.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) Levels() []log.Level {
|
||||
return []log.Level{
|
||||
log.DebugLevel,
|
||||
log.InfoLevel,
|
||||
log.WarnLevel,
|
||||
log.ErrorLevel,
|
||||
log.FatalLevel,
|
||||
log.PanicLevel,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,18 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/database"
|
||||
"github.com/genofire/logmania/lib"
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
)
|
||||
|
||||
var NotifyRegister []NotifyInit
|
||||
|
||||
type Notifier interface {
|
||||
Fire(entry *log.Entry) error
|
||||
Levels() []log.Level
|
||||
Send(entry *log.Entry) error
|
||||
Close()
|
||||
}
|
||||
|
||||
type NotifyInit func(*lib.NotifyConfig, *configNotify.NotifyState, *bot.Bot) Notifier
|
||||
type NotifyInit func(*lib.NotifyConfig, *database.DB, *bot.Bot) Notifier
|
||||
|
||||
func AddNotifier(n NotifyInit) {
|
||||
NotifyRegister = append(NotifyRegister, n)
|
||||
|
|
|
@ -3,27 +3,35 @@ package xmpp
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
xmpp "github.com/mattn/go-xmpp"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/genofire/logmania/bot"
|
||||
"github.com/genofire/logmania/database"
|
||||
"github.com/genofire/logmania/lib"
|
||||
"github.com/genofire/logmania/notify"
|
||||
configNotify "github.com/genofire/logmania/notify/config"
|
||||
)
|
||||
|
||||
var logger = log.WithField("notify", "xmpp")
|
||||
const (
|
||||
proto = "xmpp:"
|
||||
protoGroup = "xmpp-muc:"
|
||||
nickname = "logmania"
|
||||
)
|
||||
|
||||
var logger = log.WithField("notify", proto)
|
||||
|
||||
type Notifier struct {
|
||||
notify.Notifier
|
||||
client *xmpp.Client
|
||||
state *configNotify.NotifyState
|
||||
channels map[string]bool
|
||||
db *database.DB
|
||||
formatter *log.TextFormatter
|
||||
}
|
||||
|
||||
func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bot) notify.Notifier {
|
||||
func Init(config *lib.NotifyConfig, db *database.DB, bot *bot.Bot) notify.Notifier {
|
||||
options := xmpp.Options{
|
||||
Host: config.XMPP.Host,
|
||||
User: config.XMPP.Username,
|
||||
|
@ -43,6 +51,14 @@ func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bo
|
|||
for {
|
||||
chat, err := client.Recv()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
client, err = options.NewClient()
|
||||
log.Warn("reconnect")
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
logger.Warn(err)
|
||||
}
|
||||
switch v := chat.(type) {
|
||||
|
@ -53,18 +69,24 @@ func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bo
|
|||
}
|
||||
}
|
||||
}()
|
||||
for _, toAddresses := range db.HostTo {
|
||||
for to, _ := range toAddresses {
|
||||
toAddr := strings.TrimPrefix(to, protoGroup)
|
||||
client.JoinMUCNoHistory(toAddr, nickname)
|
||||
}
|
||||
}
|
||||
logger.Info("startup")
|
||||
return &Notifier{
|
||||
client: client,
|
||||
state: state,
|
||||
db: db,
|
||||
formatter: &log.TextFormatter{
|
||||
DisableTimestamp: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) Fire(e *log.Entry) error {
|
||||
e, to := n.state.SendTo(e)
|
||||
func (n *Notifier) Send(e *log.Entry) error {
|
||||
e, to := n.db.SendTo(e)
|
||||
if to == nil {
|
||||
return errors.New("no reciever found")
|
||||
}
|
||||
|
@ -73,15 +95,18 @@ func (n *Notifier) Fire(e *log.Entry) error {
|
|||
return err
|
||||
}
|
||||
for _, toAddr := range to {
|
||||
to := strings.TrimPrefix(toAddr, "xmpp:")
|
||||
if strings.Contains(toAddr, "conference") || strings.Contains(toAddr, "irc") {
|
||||
n.client.JoinMUCNoHistory(to, "logmania")
|
||||
_, err = n.client.SendHtml(xmpp.Chat{Remote: to, Type: "groupchat", Text: string(text)})
|
||||
if strings.HasPrefix(toAddr, protoGroup) {
|
||||
toAddr = strings.TrimPrefix(toAddr, protoGroup)
|
||||
if _, ok := n.channels[toAddr]; ok {
|
||||
n.client.JoinMUCNoHistory(toAddr, nickname)
|
||||
}
|
||||
_, err = n.client.SendHtml(xmpp.Chat{Remote: toAddr, Type: "groupchat", Text: string(text)})
|
||||
if err != nil {
|
||||
logger.Error("xmpp to ", to, " error:", err)
|
||||
}
|
||||
} else {
|
||||
_, err := n.client.SendHtml(xmpp.Chat{Remote: to, Type: "chat", Text: string(text)})
|
||||
toAddr = strings.TrimPrefix(toAddr, proto)
|
||||
_, err := n.client.SendHtml(xmpp.Chat{Remote: toAddr, Type: "chat", Text: string(text)})
|
||||
if err != nil {
|
||||
logger.Error("xmpp to ", to, " error:", err)
|
||||
}
|
||||
|
@ -90,19 +115,13 @@ func (n *Notifier) Fire(e *log.Entry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (n *Notifier) Levels() []log.Level {
|
||||
return []log.Level{
|
||||
log.DebugLevel,
|
||||
log.InfoLevel,
|
||||
log.WarnLevel,
|
||||
log.ErrorLevel,
|
||||
log.FatalLevel,
|
||||
log.PanicLevel,
|
||||
func (n *Notifier) Close() {
|
||||
for jid := range n.channels {
|
||||
n.client.LeaveMUC(jid)
|
||||
}
|
||||
n.client.Close()
|
||||
}
|
||||
|
||||
func (n *Notifier) Close() {}
|
||||
|
||||
func init() {
|
||||
notify.AddNotifier(Init)
|
||||
}
|
||||
|
|
|
@ -2,5 +2,6 @@ package all
|
|||
|
||||
import (
|
||||
_ "github.com/genofire/logmania/receive/journald_json"
|
||||
_ "github.com/genofire/logmania/receive/logrus"
|
||||
_ "github.com/genofire/logmania/receive/syslog"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
websocketLib "github.com/genofire/golang-lib/websocket"
|
||||
"github.com/genofire/logmania/receive/logrus"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/websocket"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// client logger
|
||||
type Logmania struct {
|
||||
URL string
|
||||
Token uuid.UUID
|
||||
Levels []log.Level
|
||||
quere chan *log.Entry
|
||||
conn *websocket.Conn
|
||||
}
|
||||
|
||||
func NewClient(url string, token uuid.UUID, lvls ...log.Level) *Logmania {
|
||||
logger := &Logmania{
|
||||
URL: url,
|
||||
Token: token,
|
||||
Levels: lvls,
|
||||
quere: make(chan *log.Entry),
|
||||
}
|
||||
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
|
||||
if err != nil {
|
||||
log.Error("[logmania] error on connect: ", err)
|
||||
return nil
|
||||
}
|
||||
logger.conn = conn
|
||||
go logger.Start()
|
||||
return logger
|
||||
}
|
||||
|
||||
// Listen if logmania server want to close the connection
|
||||
func (l *Logmania) listen() {
|
||||
for {
|
||||
var msg websocketLib.Message
|
||||
err := websocket.ReadJSON(l.conn, &msg)
|
||||
if err == io.EOF {
|
||||
l.Close()
|
||||
log.Warn("[logmania] close listener:", err)
|
||||
} else if err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
if msg.Subject == websocketLib.SessionMessageInit {
|
||||
l.conn.WriteJSON(&websocketLib.Message{
|
||||
Subject: websocketLib.SessionMessageInit,
|
||||
ID: l.Token,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logmania) writer() {
|
||||
for e := range l.quere {
|
||||
err := l.conn.WriteJSON(&websocketLib.Message{
|
||||
Subject: logrus.WS_LOG_ENTRY,
|
||||
Body: e,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("[logmania] could not send log entry:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logmania) Start() {
|
||||
go l.listen()
|
||||
l.writer()
|
||||
}
|
||||
|
||||
func (l *Logmania) Fire(e *log.Entry) {
|
||||
l.quere <- e
|
||||
}
|
||||
|
||||
// close connection to logger
|
||||
func (l *Logmania) Close() {
|
||||
l.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
||||
close(l.quere)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package client
|
|
@ -0,0 +1,55 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/genofire/golang-lib/websocket"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/genofire/logmania/lib"
|
||||
"github.com/genofire/logmania/receive"
|
||||
)
|
||||
|
||||
const WS_LOG_ENTRY = "log"
|
||||
|
||||
var logger = log.WithField("receive", "logrus")
|
||||
|
||||
type Receiver struct {
|
||||
receive.Receiver
|
||||
input chan *websocket.Message
|
||||
exportChannel chan *log.Entry
|
||||
serverSocket *websocket.Server
|
||||
}
|
||||
|
||||
func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Receiver {
|
||||
inputMsg := make(chan *websocket.Message)
|
||||
ws := websocket.NewServer(inputMsg, websocket.NewSessionManager())
|
||||
|
||||
http.HandleFunc("/receiver", ws.Handler)
|
||||
|
||||
recv := &Receiver{
|
||||
input: inputMsg,
|
||||
serverSocket: ws,
|
||||
exportChannel: exportChannel,
|
||||
}
|
||||
|
||||
logger.Info("init")
|
||||
|
||||
return recv
|
||||
}
|
||||
|
||||
func (rc *Receiver) Listen() {
|
||||
logger.Info("listen")
|
||||
for msg := range rc.input {
|
||||
if event, ok := msg.Body.(log.Entry); ok {
|
||||
rc.exportChannel <- &event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rc *Receiver) Close() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
receive.AddReceiver("websocket", Init)
|
||||
}
|
Loading…
Reference in New Issue