switch logrus and cobra
This commit is contained in:
parent
f10a4f5918
commit
2851513cfb
|
@ -6,8 +6,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
timeago "github.com/ararog/timeago"
|
timeago "github.com/ararog/timeago"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type commandFunc func(func(string), string, []string)
|
type commandFunc func(func(string), string, []string)
|
||||||
|
@ -156,11 +155,18 @@ func (b *Bot) setMaxfilter(answer func(string), from string, params []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
to := from
|
to := from
|
||||||
max := log.NewLoglevel(params[0])
|
var max log.Level
|
||||||
|
var err error
|
||||||
|
|
||||||
if len(params) > 1 {
|
if len(params) > 1 {
|
||||||
to = params[0]
|
to = params[0]
|
||||||
max = log.NewLoglevel(params[1])
|
max, err = log.ParseLevel(params[1])
|
||||||
|
} else {
|
||||||
|
max, err = log.ParseLevel(params[0])
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
answer("invalid priority: CMD Priority\n or\n CMD IPAddress Priority")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b.state.MaxPrioIn[to] = max
|
b.state.MaxPrioIn[to] = max
|
||||||
|
|
|
@ -9,7 +9,7 @@ dependencies:
|
||||||
- mkdir -p ~/.go_workspace/src/github.com/${CIRCLE_PROJECT_USERNAME}
|
- 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}
|
- ln -s ${HOME}/${CIRCLE_PROJECT_REPONAME} ${HOME}/.go_workspace/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
|
||||||
- go get -t -d -v ./...
|
- go get -t -d -v ./...
|
||||||
- go install github.com/genofire/logmania/cmd/logmania
|
- go install github.com/genofire/logmania
|
||||||
post:
|
post:
|
||||||
- cp ~/.go_workspace/bin/logmania logmania.bin
|
- cp ~/.go_workspace/bin/logmania logmania.bin
|
||||||
- tar -cvzf logmania-builded.tar.gz logmania.bin logmania_example.conf
|
- tar -cvzf logmania-builded.tar.gz logmania.bin logmania_example.conf
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
// logmania Server
|
|
||||||
//
|
|
||||||
// reload config with SIGUSR1
|
|
||||||
//
|
|
||||||
// Usage of logmania:
|
|
||||||
// -config string
|
|
||||||
// config file (default "logmania.conf")
|
|
||||||
// -debug
|
|
||||||
// enable debuging
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"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"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
configPath string
|
|
||||||
config *lib.Config
|
|
||||||
notifyState *configNotify.NotifyState
|
|
||||||
notifier notify.Notifier
|
|
||||||
receiver receive.Receiver
|
|
||||||
logChannel chan *log.Entry
|
|
||||||
logmaniaBot *bot.Bot
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.StringVar(&configPath, "config", "logmania.conf", "config file")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
config, err := lib.ReadConfig(configPath)
|
|
||||||
if config == nil || err != nil {
|
|
||||||
log.Panicf("Could not load '%s' for configuration.", configPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyState := configNotify.ReadStateFile(config.Notify.StateFile)
|
|
||||||
go notifyState.Saver(config.Notify.StateFile)
|
|
||||||
|
|
||||||
logmaniaBot = bot.NewBot(notifyState)
|
|
||||||
|
|
||||||
notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
|
|
||||||
log.Save = notifier.Send
|
|
||||||
logChannel = make(chan *log.Entry)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for a := range logChannel {
|
|
||||||
log.Save(a)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if config.Notify.AlertCheck.Duration > time.Duration(time.Second) {
|
|
||||||
go notifyState.Alert(config.Notify.AlertCheck.Duration, log.Save)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("starting logmania")
|
|
||||||
|
|
||||||
receiver = allReceiver.Init(&config.Receive, logChannel)
|
|
||||||
|
|
||||||
go receiver.Listen()
|
|
||||||
|
|
||||||
// Wait for system signal
|
|
||||||
sigchan := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGUSR1)
|
|
||||||
for sig := range sigchan {
|
|
||||||
switch sig {
|
|
||||||
case syscall.SIGTERM:
|
|
||||||
log.Panic("terminated of logmania")
|
|
||||||
os.Exit(0)
|
|
||||||
case syscall.SIGQUIT:
|
|
||||||
quit()
|
|
||||||
case syscall.SIGHUP:
|
|
||||||
quit()
|
|
||||||
case syscall.SIGUSR1:
|
|
||||||
reload()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func quit() {
|
|
||||||
receiver.Close()
|
|
||||||
notifier.Close()
|
|
||||||
log.Info("quit of logmania")
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func reload() {
|
|
||||||
log.Info("reload config file")
|
|
||||||
config, err := lib.ReadConfig(configPath)
|
|
||||||
if config == nil || err != nil {
|
|
||||||
log.Errorf("reload: could not load '%s' for new configuration. Skip reload.", configPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
receiver.Close()
|
|
||||||
receiver = allReceiver.Init(&config.Receive, logChannel)
|
|
||||||
go receiver.Listen()
|
|
||||||
|
|
||||||
notifier.Close()
|
|
||||||
notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
|
|
||||||
}
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RootCmd represents the base command when called without any subcommands
|
||||||
|
var RootCmd = &cobra.Command{
|
||||||
|
Use: "logmania",
|
||||||
|
Short: "logging centralize",
|
||||||
|
Long: `centralize logging manager`,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||||
|
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||||
|
func Execute() {
|
||||||
|
if err := RootCmd.Execute(); err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/genofire/logmania/bot"
|
||||||
|
"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
|
||||||
|
notifier notify.Notifier
|
||||||
|
receiver receive.Receiver
|
||||||
|
logChannel chan *log.Entry
|
||||||
|
logmaniaBot *bot.Bot
|
||||||
|
)
|
||||||
|
|
||||||
|
// serverCmd represents the serve command
|
||||||
|
var serverCmd = &cobra.Command{
|
||||||
|
Use: "server",
|
||||||
|
Short: "Runs the logmania server",
|
||||||
|
Example: "logmania server --config /etc/yanic.toml",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
log.SetFormatter(&log.TextFormatter{
|
||||||
|
DisableTimestamp: true,
|
||||||
|
})
|
||||||
|
config, err := lib.ReadConfig(configPath)
|
||||||
|
if config == nil || err != nil {
|
||||||
|
log.Panicf("Could not load '%s' for configuration.", configPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyState := configNotify.ReadStateFile(config.Notify.StateFile)
|
||||||
|
go notifyState.Saver(config.Notify.StateFile)
|
||||||
|
|
||||||
|
logmaniaBot = bot.NewBot(notifyState)
|
||||||
|
|
||||||
|
notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
|
||||||
|
log.AddHook(notifier)
|
||||||
|
logChannel = make(chan *log.Entry)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for a := range logChannel {
|
||||||
|
notifier.Fire(a)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if config.Notify.AlertCheck.Duration > time.Duration(time.Second) {
|
||||||
|
go notifyState.Alert(config.Notify.AlertCheck.Duration, notifier.Fire)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("starting logmania")
|
||||||
|
|
||||||
|
receiver = allReceiver.Init(&config.Receive, logChannel)
|
||||||
|
|
||||||
|
go receiver.Listen()
|
||||||
|
|
||||||
|
// Wait for system signal
|
||||||
|
sigchan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGUSR1)
|
||||||
|
for sig := range sigchan {
|
||||||
|
switch sig {
|
||||||
|
case syscall.SIGTERM:
|
||||||
|
log.Panic("terminated of logmania")
|
||||||
|
os.Exit(0)
|
||||||
|
case syscall.SIGQUIT:
|
||||||
|
quit()
|
||||||
|
case syscall.SIGHUP:
|
||||||
|
quit()
|
||||||
|
case syscall.SIGUSR1:
|
||||||
|
reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func quit() {
|
||||||
|
receiver.Close()
|
||||||
|
notifier.Close()
|
||||||
|
log.Info("quit of logmania")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reload() {
|
||||||
|
log.Info("reload config file")
|
||||||
|
config, err := lib.ReadConfig(configPath)
|
||||||
|
if config == nil || err != nil {
|
||||||
|
log.Errorf("reload: could not load '%s' for new configuration. Skip reload.", configPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
receiver.Close()
|
||||||
|
receiver = allReceiver.Init(&config.Receive, logChannel)
|
||||||
|
go receiver.Listen()
|
||||||
|
|
||||||
|
notifier.Close()
|
||||||
|
notifier = allNotify.Init(&config.Notify, notifyState, logmaniaBot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RootCmd.AddCommand(serverCmd)
|
||||||
|
serverCmd.Flags().StringVarP(&configPath, "config", "c", "logmania.conf", "Path to configuration file")
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
|
||||||
"github.com/genofire/logmania/log"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Struct of the configuration
|
// Struct of the configuration
|
||||||
|
|
|
@ -45,7 +45,7 @@ func Parse(binaryMsg []byte) *SyslogMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.Content = match[2][timeLength:]
|
msg.Content = strings.TrimLeft(match[2][timeLength:], " ")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: detect other parts in content
|
TODO: detect other parts in content
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
package client
|
|
||||||
|
|
||||||
/* logger to bind at github.com/genofire/logmania/log.AddLogger to send log entries to logmania server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
|
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// client logger
|
|
||||||
type Logger struct {
|
|
||||||
log.Logger
|
|
||||||
AboveLevel log.LogLevel
|
|
||||||
conn *websocket.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
const LOGGER_NAME = "client"
|
|
||||||
|
|
||||||
// CurrentLogger (for override settings e.g. AboveLevel)
|
|
||||||
var CurrentLogger *Logger
|
|
||||||
|
|
||||||
// create a new logmania client logger
|
|
||||||
func NewLogger(url, token string, AboveLevel log.LogLevel) *Logger {
|
|
||||||
c, _, err := websocket.DefaultDialer.Dial(fmt.Sprint(url, "/logger"), nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("[logmania] error on connect: ", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err = c.WriteMessage(websocket.TextMessage, []byte(token))
|
|
||||||
if err != nil {
|
|
||||||
log.Error("[logmania] could not send token:", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &Logger{
|
|
||||||
AboveLevel: AboveLevel,
|
|
||||||
conn: c,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle a log entry (send to logmania server)
|
|
||||||
func (l *Logger) Hook(e *log.Entry) {
|
|
||||||
if e.Level < l.AboveLevel {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := l.conn.WriteJSON(e)
|
|
||||||
if err != nil {
|
|
||||||
l.Close()
|
|
||||||
log.Error("[logmania] could not send log entry:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen if logmania server want to close the connection
|
|
||||||
func (l *Logger) Listen() {
|
|
||||||
for {
|
|
||||||
msgType, _, err := l.conn.ReadMessage()
|
|
||||||
if msgType == -1 {
|
|
||||||
l.conn.Close()
|
|
||||||
l.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
l.Close()
|
|
||||||
log.Warn("[logmania] close listener:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// close connection to logger
|
|
||||||
func (l *Logger) Close() {
|
|
||||||
l.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
|
||||||
log.RemoveLogger(LOGGER_NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
// init logmania's client logger and bind
|
|
||||||
func Init(url, token string, AboveLevel log.LogLevel) *Logger {
|
|
||||||
CurrentLogger = NewLogger(url, token, AboveLevel)
|
|
||||||
go CurrentLogger.Listen()
|
|
||||||
log.AddLogger(LOGGER_NAME, CurrentLogger)
|
|
||||||
return CurrentLogger
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -1 +0,0 @@
|
||||||
package client
|
|
46
log/init.go
46
log/init.go
|
@ -1,46 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
wsGozilla "github.com/gorilla/websocket"
|
|
||||||
"golang.org/x/net/websocket"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getIP(r *http.Request) string {
|
|
||||||
ip := r.Header.Get("X-Forwarded-For")
|
|
||||||
if ip == "" {
|
|
||||||
ip = r.RemoteAddr
|
|
||||||
}
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
|
|
||||||
// init log entry with extra fields of interesting http request context
|
|
||||||
func HTTP(r *http.Request) *Entry {
|
|
||||||
return New().AddFields(map[string]interface{}{
|
|
||||||
"remote": getIP(r),
|
|
||||||
"method": r.Method,
|
|
||||||
"url": r.URL.RequestURI(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// init log entry with extra fields of interesting websocket request context
|
|
||||||
func WebsocketX(ws *websocket.Conn) *Entry {
|
|
||||||
r := ws.Request()
|
|
||||||
if r == nil {
|
|
||||||
return New().AddField("websocket", true)
|
|
||||||
}
|
|
||||||
return New().AddFields(map[string]interface{}{
|
|
||||||
"remote": getIP(r),
|
|
||||||
"websocket": true,
|
|
||||||
"url": r.URL.RequestURI(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// init log entry with extra fields of interesting websocket request context
|
|
||||||
func WebsocketGozilla(ws *wsGozilla.Conn) *Entry {
|
|
||||||
return New().AddFields(map[string]interface{}{
|
|
||||||
"remote": ws.RemoteAddr().String(),
|
|
||||||
"websocket": true,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"golang.org/x/net/websocket"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetIP(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
req, _ := http.NewRequest("GET", "https://google.com/lola/duda?q=wasd", nil)
|
|
||||||
req.RemoteAddr = "127.0.0.1"
|
|
||||||
assert.Equal("127.0.0.1", getIP(req))
|
|
||||||
req.Header.Set("X-Forwarded-For", "8.8.8.8")
|
|
||||||
assert.Equal("8.8.8.8", getIP(req))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHTTP(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
req, _ := http.NewRequest("GET", "https://google.com/lola/duda?q=wasd", nil)
|
|
||||||
entry := HTTP(req)
|
|
||||||
_, ok := entry.Fields["remote"]
|
|
||||||
|
|
||||||
assert.NotNil(ok, "remote address not set in logger")
|
|
||||||
assert.Equal("GET", entry.Fields["method"], "method not set in logger")
|
|
||||||
assert.Equal("/lola/duda?q=wasd", entry.Fields["url"], "path not set in logger")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWebsocketX(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
ws := &websocket.Conn{}
|
|
||||||
entry := WebsocketX(ws)
|
|
||||||
_, ok := entry.Fields["remote"]
|
|
||||||
|
|
||||||
assert.NotNil(ok, "remote address not set in logger")
|
|
||||||
assert.True(entry.Fields["websocket"].(bool))
|
|
||||||
}
|
|
156
log/level.go
156
log/level.go
|
@ -1,156 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
// definition of loglevel
|
|
||||||
type LogLevel int32
|
|
||||||
|
|
||||||
// accepted LogLevels and his internal int values
|
|
||||||
const (
|
|
||||||
DebugLevel = LogLevel(-1)
|
|
||||||
InfoLevel = LogLevel(0)
|
|
||||||
WarnLevel = LogLevel(1)
|
|
||||||
ErrorLevel = LogLevel(2)
|
|
||||||
PanicLevel = LogLevel(3)
|
|
||||||
)
|
|
||||||
|
|
||||||
// string of loglevel
|
|
||||||
func (l LogLevel) String() string {
|
|
||||||
switch l {
|
|
||||||
case DebugLevel:
|
|
||||||
return "Debug"
|
|
||||||
case InfoLevel:
|
|
||||||
return "Info"
|
|
||||||
case WarnLevel:
|
|
||||||
return "Warn"
|
|
||||||
case ErrorLevel:
|
|
||||||
return "ERROR"
|
|
||||||
case PanicLevel:
|
|
||||||
return "PANIC"
|
|
||||||
|
|
||||||
}
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
// close logentry with debug
|
|
||||||
func (e *Entry) Debug(v ...interface{}) {
|
|
||||||
e.Log(DebugLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with formated debug
|
|
||||||
func (e *Entry) Debugf(format string, v ...interface{}) {
|
|
||||||
e.Logf(DebugLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with info
|
|
||||||
func (e *Entry) Info(v ...interface{}) {
|
|
||||||
e.Log(InfoLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with formated info
|
|
||||||
func (e *Entry) Infof(format string, v ...interface{}) {
|
|
||||||
e.Logf(InfoLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with warning
|
|
||||||
func (e *Entry) Warn(v ...interface{}) {
|
|
||||||
e.Log(WarnLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with formated warning
|
|
||||||
func (e *Entry) Warnf(format string, v ...interface{}) {
|
|
||||||
e.Logf(WarnLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with error
|
|
||||||
func (e *Entry) Error(v ...interface{}) {
|
|
||||||
e.Log(ErrorLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with formated error
|
|
||||||
func (e *Entry) Errorf(format string, v ...interface{}) {
|
|
||||||
e.Logf(ErrorLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with panic
|
|
||||||
func (e *Entry) Panic(v ...interface{}) {
|
|
||||||
e.Log(PanicLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close logentry with formated panic
|
|
||||||
func (e *Entry) Panicf(format string, v ...interface{}) {
|
|
||||||
e.Logf(PanicLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direct log command
|
|
||||||
*/
|
|
||||||
|
|
||||||
// direct log with debug
|
|
||||||
func Debug(v ...interface{}) {
|
|
||||||
New().Log(DebugLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with formated debug
|
|
||||||
func Debugf(format string, v ...interface{}) {
|
|
||||||
New().Logf(DebugLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with info
|
|
||||||
func Info(v ...interface{}) {
|
|
||||||
New().Log(InfoLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with formated info
|
|
||||||
func Infof(format string, v ...interface{}) {
|
|
||||||
New().Logf(InfoLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with warning
|
|
||||||
func Warn(v ...interface{}) {
|
|
||||||
New().Log(WarnLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with formated warning
|
|
||||||
func Warnf(format string, v ...interface{}) {
|
|
||||||
New().Logf(WarnLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with error
|
|
||||||
func Error(v ...interface{}) {
|
|
||||||
New().Log(ErrorLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with formated error
|
|
||||||
func Errorf(format string, v ...interface{}) {
|
|
||||||
New().Logf(ErrorLevel, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with panic
|
|
||||||
func Panic(v ...interface{}) {
|
|
||||||
New().Log(PanicLevel, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct log with formated panic
|
|
||||||
func Panicf(format string, v ...interface{}) {
|
|
||||||
New().Logf(PanicLevel, format, v...)
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
type loggerFunc func(*Entry)
|
|
||||||
|
|
||||||
var Save loggerFunc
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
Save = func(*Entry) {}
|
|
||||||
}
|
|
55
log/main.go
55
log/main.go
|
@ -1,55 +0,0 @@
|
||||||
// log package with entry as a lib in other go applications
|
|
||||||
package log
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// a struct with all information of a log entry
|
|
||||||
type Entry struct {
|
|
||||||
Level LogLevel `json:"level"`
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
Service string `json:"service"`
|
|
||||||
Fields map[string]interface{} `json:"fields"`
|
|
||||||
Text string `json:"text"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save/out current state of log entry
|
|
||||||
func (e *Entry) Log(level LogLevel, v ...interface{}) {
|
|
||||||
e.Text = fmt.Sprint(v...)
|
|
||||||
e.Level = level
|
|
||||||
Save(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save/out current state of log entry with formation
|
|
||||||
func (e *Entry) Logf(level LogLevel, format string, v ...interface{}) {
|
|
||||||
e.Text = fmt.Sprintf(format, v...)
|
|
||||||
e.Level = level
|
|
||||||
Save(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// init new log entry
|
|
||||||
func New() *Entry {
|
|
||||||
return &Entry{Fields: make(map[string]interface{})}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add extra value to entry (log entry with context)
|
|
||||||
func (e *Entry) AddField(key string, value interface{}) *Entry {
|
|
||||||
e.Fields[key] = value
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// add multi extra values to entry (log entry with context)
|
|
||||||
func (e *Entry) AddFields(fields map[string]interface{}) *Entry {
|
|
||||||
for key, value := range fields {
|
|
||||||
e.Fields[key] = value
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a readable string of extra values (log entry with context)
|
|
||||||
func (e *Entry) FieldString() string {
|
|
||||||
text := ""
|
|
||||||
for key, value := range e.Fields {
|
|
||||||
text = fmt.Sprintf("%s %s=%v", text, key, value)
|
|
||||||
}
|
|
||||||
return text[1:]
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLog(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
//save := func(e *Entry) {}
|
|
||||||
entry := New()
|
|
||||||
assert.Equal(0, int(entry.Level))
|
|
||||||
assert.Equal("", entry.Text)
|
|
||||||
|
|
||||||
entry.Log(WarnLevel, "blub")
|
|
||||||
assert.Equal(1, int(entry.Level))
|
|
||||||
assert.Equal("blub", entry.Text)
|
|
||||||
|
|
||||||
entry.Logf(ErrorLevel, "lola %.1f", 13.13431)
|
|
||||||
assert.Equal(2, int(entry.Level))
|
|
||||||
assert.Equal("lola 13.1", entry.Text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddFields(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
entry := New()
|
|
||||||
assert.Len(entry.Fields, 0)
|
|
||||||
|
|
||||||
entry.AddField("a", "lola")
|
|
||||||
assert.Len(entry.Fields, 1)
|
|
||||||
assert.Equal("lola", entry.Fields["a"])
|
|
||||||
|
|
||||||
entry.AddFields(map[string]interface{}{"a": 232., "foo": "bar"})
|
|
||||||
assert.Len(entry.Fields, 2)
|
|
||||||
assert.Equal(232.0, entry.Fields["a"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFieldString(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
entry := New()
|
|
||||||
entry.AddFields(map[string]interface{}{"a": 232., "foo": "bar"})
|
|
||||||
str := entry.FieldString()
|
|
||||||
assert.Contains(str, "a=232")
|
|
||||||
assert.Contains(str, "foo=bar")
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/genofire/logmania/cmd"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Execute()
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
package all
|
package all
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/genofire/logmania/bot"
|
"github.com/genofire/logmania/bot"
|
||||||
"github.com/genofire/logmania/lib"
|
"github.com/genofire/logmania/lib"
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
"github.com/genofire/logmania/notify"
|
"github.com/genofire/logmania/notify"
|
||||||
configNotify "github.com/genofire/logmania/notify/config"
|
configNotify "github.com/genofire/logmania/notify/config"
|
||||||
)
|
)
|
||||||
|
@ -36,13 +37,14 @@ func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bo
|
||||||
func (n *Notifier) sender() {
|
func (n *Notifier) sender() {
|
||||||
for c := range n.channelNotify {
|
for c := range n.channelNotify {
|
||||||
for _, item := range n.list {
|
for _, item := range n.list {
|
||||||
item.Send(c)
|
item.Fire(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) Send(e *log.Entry) {
|
func (n *Notifier) Fire(e *log.Entry) error {
|
||||||
n.channelNotify <- e
|
n.channelNotify <- e
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) Close() {
|
func (n *Notifier) Close() {
|
||||||
|
@ -50,3 +52,14 @@ func (n *Notifier) Close() {
|
||||||
item.Close()
|
item.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Notifier) Levels() []log.Level {
|
||||||
|
return []log.Level{
|
||||||
|
log.DebugLevel,
|
||||||
|
log.InfoLevel,
|
||||||
|
log.WarnLevel,
|
||||||
|
log.ErrorLevel,
|
||||||
|
log.FatalLevel,
|
||||||
|
log.PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package all
|
package all
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/genofire/logmania/notify/console"
|
|
||||||
_ "github.com/genofire/logmania/notify/xmpp"
|
_ "github.com/genofire/logmania/notify/xmpp"
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,12 +2,11 @@ package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/genofire/logmania/log"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const AlertMsg = "alert service from logmania, device did not send new message for a while"
|
const AlertMsg = "alert service from logmania, device did not send new message for a while"
|
||||||
|
@ -15,26 +14,30 @@ const AlertMsg = "alert service from logmania, device did not send new message f
|
||||||
type NotifyState struct {
|
type NotifyState struct {
|
||||||
Hostname map[string]string `json:"hostname"`
|
Hostname map[string]string `json:"hostname"`
|
||||||
HostTo map[string]map[string]bool `json:"host_to"`
|
HostTo map[string]map[string]bool `json:"host_to"`
|
||||||
MaxPrioIn map[string]log.LogLevel `json:"maxLevel"`
|
MaxPrioIn map[string]log.Level `json:"maxLevel"`
|
||||||
RegexIn map[string]map[string]*regexp.Regexp `json:"regexIn"`
|
RegexIn map[string]map[string]*regexp.Regexp `json:"regexIn"`
|
||||||
Lastseen map[string]time.Time `json:"lastseen,omitempty"`
|
Lastseen map[string]time.Time `json:"lastseen,omitempty"`
|
||||||
LastseenNotify map[string]time.Time `json:"-"`
|
LastseenNotify map[string]time.Time `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *NotifyState) SendTo(e *log.Entry) []string {
|
func (state *NotifyState) SendTo(e *log.Entry) []string {
|
||||||
if to, ok := state.HostTo[e.Hostname]; ok {
|
hostname, ok := e.Data["hostname"].(string)
|
||||||
if e.Text != AlertMsg && e.Hostname != "" {
|
if !ok {
|
||||||
state.Lastseen[e.Hostname] = time.Now()
|
return nil
|
||||||
|
}
|
||||||
|
if to, ok := state.HostTo[hostname]; ok {
|
||||||
|
if e.Message != AlertMsg && hostname != "" {
|
||||||
|
state.Lastseen[hostname] = time.Now()
|
||||||
}
|
}
|
||||||
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
|
||||||
}
|
}
|
||||||
if regex, ok := state.RegexIn[toEntry]; ok {
|
if regex, ok := state.RegexIn[toEntry]; ok {
|
||||||
stopForTo := false
|
stopForTo := false
|
||||||
for _, expr := range regex {
|
for _, expr := range regex {
|
||||||
if expr.MatchString(e.Text) {
|
if expr.MatchString(e.Message) {
|
||||||
stopForTo = true
|
stopForTo = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -45,12 +48,12 @@ func (state *NotifyState) SendTo(e *log.Entry) []string {
|
||||||
}
|
}
|
||||||
toList = append(toList, toEntry)
|
toList = append(toList, toEntry)
|
||||||
}
|
}
|
||||||
if hostname, ok := state.Hostname[e.Hostname]; ok {
|
if replaceHostname, ok := state.Hostname[hostname]; ok {
|
||||||
e.Hostname = hostname
|
e.WithField("hostname", replaceHostname)
|
||||||
}
|
}
|
||||||
return toList
|
return toList
|
||||||
} else {
|
} else {
|
||||||
state.HostTo[e.Hostname] = make(map[string]bool)
|
state.HostTo[hostname] = make(map[string]bool)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -71,7 +74,7 @@ func ReadStateFile(path string) *NotifyState {
|
||||||
var state NotifyState
|
var state NotifyState
|
||||||
if f, err := os.Open(path); err == nil { // transform data to legacy meshviewer
|
if f, err := os.Open(path); err == nil { // transform data to legacy meshviewer
|
||||||
if err = json.NewDecoder(f).Decode(&state); err == nil {
|
if err = json.NewDecoder(f).Decode(&state); err == nil {
|
||||||
fmt.Println("loaded", len(state.HostTo), "hosts")
|
log.Infof("loaded %d hosts", len(state.HostTo))
|
||||||
if state.Lastseen == nil {
|
if state.Lastseen == nil {
|
||||||
state.Lastseen = make(map[string]time.Time)
|
state.Lastseen = make(map[string]time.Time)
|
||||||
}
|
}
|
||||||
|
@ -89,15 +92,15 @@ func ReadStateFile(path string) *NotifyState {
|
||||||
}
|
}
|
||||||
return &state
|
return &state
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("failed to unmarshal nodes:", err)
|
log.Error("failed to unmarshal nodes:", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("failed to open state notify file: ", path, ":", err)
|
log.Error("failed to open state notify file: ", path, ":", err)
|
||||||
}
|
}
|
||||||
return &NotifyState{
|
return &NotifyState{
|
||||||
Hostname: make(map[string]string),
|
Hostname: make(map[string]string),
|
||||||
HostTo: make(map[string]map[string]bool),
|
HostTo: make(map[string]map[string]bool),
|
||||||
MaxPrioIn: make(map[string]log.LogLevel),
|
MaxPrioIn: make(map[string]log.Level),
|
||||||
RegexIn: make(map[string]map[string]*regexp.Regexp),
|
RegexIn: make(map[string]map[string]*regexp.Regexp),
|
||||||
Lastseen: make(map[string]time.Time),
|
Lastseen: make(map[string]time.Time),
|
||||||
LastseenNotify: make(map[string]time.Time),
|
LastseenNotify: make(map[string]time.Time),
|
||||||
|
@ -112,7 +115,7 @@ func (state *NotifyState) Saver(path string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *NotifyState) Alert(expired time.Duration, send func(e *log.Entry)) {
|
func (state *NotifyState) Alert(expired time.Duration, send func(e *log.Entry) error) {
|
||||||
c := time.Tick(time.Minute)
|
c := time.Tick(time.Minute)
|
||||||
|
|
||||||
for range c {
|
for range c {
|
||||||
|
@ -121,11 +124,11 @@ func (state *NotifyState) Alert(expired time.Duration, send func(e *log.Entry))
|
||||||
if time.Before(now.Add(expired * -2)) {
|
if time.Before(now.Add(expired * -2)) {
|
||||||
if timeNotify, ok := state.LastseenNotify[host]; !ok || !time.Before(timeNotify) {
|
if timeNotify, ok := state.LastseenNotify[host]; !ok || !time.Before(timeNotify) {
|
||||||
state.LastseenNotify[host] = now
|
state.LastseenNotify[host] = now
|
||||||
send(&log.Entry{
|
entry := log.NewEntry(log.New())
|
||||||
Hostname: host,
|
entry.Level = log.ErrorLevel
|
||||||
Level: log.ErrorLevel,
|
entry.Message = AlertMsg
|
||||||
Text: AlertMsg,
|
entry.WithField("hostname", host)
|
||||||
})
|
send(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
package console
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"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 (
|
|
||||||
errOutput io.Writer = os.Stderr
|
|
||||||
output io.Writer = os.Stdout
|
|
||||||
)
|
|
||||||
|
|
||||||
// logger for output
|
|
||||||
type Notifier struct {
|
|
||||||
notify.Notifier
|
|
||||||
TimeFormat string
|
|
||||||
ShowTime bool
|
|
||||||
Debug bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bot) notify.Notifier {
|
|
||||||
return &Notifier{
|
|
||||||
TimeFormat: "2006-01-02 15:04:05",
|
|
||||||
ShowTime: true,
|
|
||||||
Debug: config.Console,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle a log entry (print it on the terminal with color)
|
|
||||||
func (n *Notifier) Send(e *log.Entry) {
|
|
||||||
if e == nil || n == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if e.Hostname != "" && !n.Debug {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v := []interface{}{}
|
|
||||||
format := "[%s]"
|
|
||||||
|
|
||||||
if n.ShowTime {
|
|
||||||
format = "%s [%s]"
|
|
||||||
v = append(v, color.LightBlue(time.Now().Format(n.TimeFormat)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hostname and Service
|
|
||||||
if e.Hostname != "" && e.Service != "" {
|
|
||||||
format = fmt.Sprintf("%s [%%s-%%s]", format)
|
|
||||||
v = append(v, color.Purple(e.Hostname), color.Cyan(e.Service))
|
|
||||||
} else if e.Hostname != "" {
|
|
||||||
format = fmt.Sprintf("%s [%%s]", format)
|
|
||||||
v = append(v, color.Purple(e.Hostname))
|
|
||||||
} else if e.Service != "" {
|
|
||||||
format = fmt.Sprintf("%s [%%s]", format)
|
|
||||||
v = append(v, color.Cyan(e.Service))
|
|
||||||
}
|
|
||||||
|
|
||||||
format = fmt.Sprintf("%s %%s", format)
|
|
||||||
lvl := e.Level.String()
|
|
||||||
switch e.Level {
|
|
||||||
case log.DebugLevel:
|
|
||||||
lvl = color.DarkGray(lvl)
|
|
||||||
case log.InfoLevel:
|
|
||||||
lvl = color.Green(lvl)
|
|
||||||
case log.WarnLevel:
|
|
||||||
lvl = color.Yellow(lvl)
|
|
||||||
case log.ErrorLevel:
|
|
||||||
lvl = color.Red(lvl)
|
|
||||||
case log.PanicLevel:
|
|
||||||
lvl = color.BRed(lvl)
|
|
||||||
}
|
|
||||||
|
|
||||||
v = append(v, lvl, e.Text)
|
|
||||||
|
|
||||||
if len(e.Fields) > 0 {
|
|
||||||
v = append(v, color.Purple(e.FieldString()))
|
|
||||||
format = fmt.Sprintf("%s (%%s)\n", format)
|
|
||||||
} else {
|
|
||||||
format = fmt.Sprintf("%s\n", format)
|
|
||||||
}
|
|
||||||
|
|
||||||
text := fmt.Sprintf(format, v...)
|
|
||||||
|
|
||||||
if e.Level > log.WarnLevel {
|
|
||||||
errOutput.Write([]byte(text))
|
|
||||||
} else {
|
|
||||||
output.Write([]byte(text))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Notifier) Close() {}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
notify.AddNotifier(Init)
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package console
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func captureOutput(f func()) (string, string) {
|
|
||||||
var bufErrOutput bytes.Buffer
|
|
||||||
var bufOutput bytes.Buffer
|
|
||||||
errOutput = &bufErrOutput
|
|
||||||
output = &bufOutput
|
|
||||||
f()
|
|
||||||
errOutput = os.Stderr
|
|
||||||
output = os.Stdout
|
|
||||||
return bufOutput.String(), bufErrOutput.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warning: colors are not tested (it should be in the imported package)
|
|
||||||
func TestOutput(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
assert.True(true)
|
|
||||||
out, err := captureOutput(func() {
|
|
||||||
log.Info("test")
|
|
||||||
})
|
|
||||||
assert.Equal("", err)
|
|
||||||
|
|
||||||
out, err = captureOutput(func() {
|
|
||||||
log.Warn("test")
|
|
||||||
})
|
|
||||||
assert.NotRegexp("-.*\\[.{5}Warn.{4}\\] test", out)
|
|
||||||
assert.Equal("", err)
|
|
||||||
|
|
||||||
out, err = captureOutput(func() {
|
|
||||||
log.Error("test")
|
|
||||||
})
|
|
||||||
assert.Equal("", out)
|
|
||||||
|
|
||||||
out, err = captureOutput(func() {
|
|
||||||
log.Debug("test")
|
|
||||||
})
|
|
||||||
assert.Equal("", out)
|
|
||||||
assert.Equal("", err)
|
|
||||||
|
|
||||||
out, err = captureOutput(func() {
|
|
||||||
log.Info("test")
|
|
||||||
})
|
|
||||||
assert.Equal("", out)
|
|
||||||
assert.Equal("", err)
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,16 +1,18 @@
|
||||||
package notify
|
package notify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/genofire/logmania/bot"
|
"github.com/genofire/logmania/bot"
|
||||||
"github.com/genofire/logmania/lib"
|
"github.com/genofire/logmania/lib"
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
configNotify "github.com/genofire/logmania/notify/config"
|
configNotify "github.com/genofire/logmania/notify/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
var NotifyRegister []NotifyInit
|
var NotifyRegister []NotifyInit
|
||||||
|
|
||||||
type Notifier interface {
|
type Notifier interface {
|
||||||
Send(entry *log.Entry)
|
Fire(entry *log.Entry) error
|
||||||
|
Levels() []log.Level
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package xmpp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func formatEntry(e *log.Entry) string {
|
|
||||||
if e.Hostname != "" && e.Service != "" {
|
|
||||||
return fmt.Sprintf("[%s-%s] [%s] %s", e.Hostname, e.Service, e.Level, e.Text)
|
|
||||||
|
|
||||||
} else if e.Hostname != "" {
|
|
||||||
return fmt.Sprintf("[%s] [%s] %s", e.Hostname, e.Level, e.Text)
|
|
||||||
|
|
||||||
} else if e.Service != "" {
|
|
||||||
return fmt.Sprintf("[%s] [%s] %s", e.Service, e.Level, e.Text)
|
|
||||||
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("[%s] %s", e.Level, e.Text)
|
|
||||||
}
|
|
|
@ -1,22 +1,26 @@
|
||||||
package xmpp
|
package xmpp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
xmpp "github.com/mattn/go-xmpp"
|
xmpp "github.com/mattn/go-xmpp"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/genofire/logmania/bot"
|
"github.com/genofire/logmania/bot"
|
||||||
"github.com/genofire/logmania/lib"
|
"github.com/genofire/logmania/lib"
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
"github.com/genofire/logmania/notify"
|
"github.com/genofire/logmania/notify"
|
||||||
configNotify "github.com/genofire/logmania/notify/config"
|
configNotify "github.com/genofire/logmania/notify/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var logger = log.WithField("notify", "xmpp")
|
||||||
|
|
||||||
type Notifier struct {
|
type Notifier struct {
|
||||||
notify.Notifier
|
notify.Notifier
|
||||||
client *xmpp.Client
|
client *xmpp.Client
|
||||||
state *configNotify.NotifyState
|
state *configNotify.NotifyState
|
||||||
|
formatter *log.TextFormatter
|
||||||
}
|
}
|
||||||
|
|
||||||
func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bot) notify.Notifier {
|
func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bot) notify.Notifier {
|
||||||
|
@ -32,13 +36,14 @@ func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bo
|
||||||
}
|
}
|
||||||
client, err := options.NewClient()
|
client, err := options.NewClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
chat, err := client.Recv()
|
chat, err := client.Recv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(err)
|
logger.Warn(err)
|
||||||
}
|
}
|
||||||
switch v := chat.(type) {
|
switch v := chat.(type) {
|
||||||
case xmpp.Chat:
|
case xmpp.Chat:
|
||||||
|
@ -48,30 +53,52 @@ func Init(config *lib.NotifyConfig, state *configNotify.NotifyState, bot *bot.Bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
log.Info("xmpp startup")
|
logger.Info("startup")
|
||||||
return &Notifier{client: client, state: state}
|
return &Notifier{
|
||||||
|
client: client,
|
||||||
|
state: state,
|
||||||
|
formatter: &log.TextFormatter{
|
||||||
|
DisableTimestamp: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) Send(e *log.Entry) {
|
func (n *Notifier) Fire(e *log.Entry) error {
|
||||||
to := n.state.SendTo(e)
|
to := n.state.SendTo(e)
|
||||||
if to == nil {
|
if to == nil {
|
||||||
return
|
return errors.New("no reciever found")
|
||||||
|
}
|
||||||
|
text, err := n.formatter.Format(e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
for _, toAddr := range to {
|
for _, toAddr := range to {
|
||||||
to := strings.TrimPrefix(toAddr, "xmpp:")
|
to := strings.TrimPrefix(toAddr, "xmpp:")
|
||||||
if strings.Contains(toAddr, "conference") || strings.Contains(toAddr, "irc") {
|
if strings.Contains(toAddr, "conference") || strings.Contains(toAddr, "irc") {
|
||||||
n.client.JoinMUCNoHistory(to, "logmania")
|
n.client.JoinMUCNoHistory(to, "logmania")
|
||||||
_, err := n.client.SendHtml(xmpp.Chat{Remote: to, Type: "groupchat", Text: formatEntry(e)})
|
_, err = n.client.SendHtml(xmpp.Chat{Remote: to, Type: "groupchat", Text: string(text)})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("xmpp to ", to, " error:", err)
|
logger.Error("xmpp to ", to, " error:", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, err := n.client.SendHtml(xmpp.Chat{Remote: to, Type: "chat", Text: formatEntry(e)})
|
_, err := n.client.SendHtml(xmpp.Chat{Remote: to, Type: "chat", Text: string(text)})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("xmpp to ", to, " error:", err)
|
logger.Error("xmpp to ", to, " error:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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() {}
|
func (n *Notifier) Close() {}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package all
|
package all
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/genofire/logmania/lib"
|
"github.com/genofire/logmania/lib"
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
"github.com/genofire/logmania/receive"
|
"github.com/genofire/logmania/receive"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/genofire/logmania/log"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JournalMessage struct {
|
type JournalMessage struct {
|
||||||
|
@ -34,7 +34,7 @@ type JournalMessage struct {
|
||||||
Message string `json:"MESSAGE"`
|
Message string `json:"MESSAGE"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var PriorityMap = map[int]log.LogLevel{
|
var PriorityMap = map[int]log.Level{
|
||||||
0: log.PanicLevel, // emerg
|
0: log.PanicLevel, // emerg
|
||||||
1: log.PanicLevel, // alert
|
1: log.PanicLevel, // alert
|
||||||
2: log.PanicLevel, // crit
|
2: log.PanicLevel, // crit
|
||||||
|
@ -57,15 +57,16 @@ func toLogEntry(msg []byte, from string) *log.Entry {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
e := &log.Entry{
|
entry := log.NewEntry(nil)
|
||||||
Level: PriorityMap[prio],
|
entry = entry.WithFields(mapEntry)
|
||||||
Hostname: from,
|
entry = entry.WithFields(log.Fields{
|
||||||
Service: data.SyslogIdentifier,
|
"hostname": from,
|
||||||
Text: data.Message,
|
"service": data.SyslogIdentifier,
|
||||||
Fields: mapEntry,
|
})
|
||||||
}
|
|
||||||
if data.SystemdUnit == "" {
|
if data.SystemdUnit == "" {
|
||||||
e.Service = data.SystemdUnit
|
entry = entry.WithField("service", data.SystemdUnit)
|
||||||
}
|
}
|
||||||
return e
|
entry.Level = PriorityMap[prio]
|
||||||
|
entry.Message = data.Message
|
||||||
|
return entry
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,14 @@ package journald_json
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/genofire/logmania/lib"
|
"github.com/genofire/logmania/lib"
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
"github.com/genofire/logmania/receive"
|
"github.com/genofire/logmania/receive"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var logger = log.WithField("receive", "journald_json")
|
||||||
|
|
||||||
type Receiver struct {
|
type Receiver struct {
|
||||||
receive.Receiver
|
receive.Receiver
|
||||||
exportChannel chan *log.Entry
|
exportChannel chan *log.Entry
|
||||||
|
@ -19,7 +22,7 @@ func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Rece
|
||||||
ln, err := net.ListenUDP(config.JournaldJSON.Type, addr)
|
ln, err := net.ListenUDP(config.JournaldJSON.Type, addr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("journald-json init ", err)
|
logger.Error("init ", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
recv := &Receiver{
|
recv := &Receiver{
|
||||||
|
@ -27,7 +30,7 @@ func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Rece
|
||||||
exportChannel: exportChannel,
|
exportChannel: exportChannel,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("journald-json init")
|
logger.Info("init")
|
||||||
|
|
||||||
return recv
|
return recv
|
||||||
}
|
}
|
||||||
|
@ -35,12 +38,12 @@ func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Rece
|
||||||
const maxDataGramSize = 8192
|
const maxDataGramSize = 8192
|
||||||
|
|
||||||
func (rc *Receiver) Listen() {
|
func (rc *Receiver) Listen() {
|
||||||
log.Info("journald-json listen")
|
logger.Info("listen")
|
||||||
for {
|
for {
|
||||||
buf := make([]byte, maxDataGramSize)
|
buf := make([]byte, maxDataGramSize)
|
||||||
n, src, err := rc.serverSocket.ReadFromUDP(buf)
|
n, src, err := rc.serverSocket.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("failed to accept connection", err)
|
logger.Warn("failed to accept connection", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ package receive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/genofire/logmania/lib"
|
"github.com/genofire/logmania/lib"
|
||||||
"github.com/genofire/logmania/log"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Register = make(map[string]ReceiverInit)
|
var Register = make(map[string]ReceiverInit)
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package syslog
|
package syslog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
libSyslog "github.com/genofire/logmania/lib/syslog"
|
libSyslog "github.com/genofire/logmania/lib/syslog"
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var SyslogPriorityMap = map[int]log.LogLevel{
|
var SyslogPriorityMap = map[int]log.Level{
|
||||||
0: log.PanicLevel,
|
0: log.PanicLevel,
|
||||||
1: log.PanicLevel,
|
1: log.PanicLevel,
|
||||||
2: log.PanicLevel,
|
2: log.PanicLevel,
|
||||||
|
@ -19,9 +20,10 @@ var SyslogPriorityMap = map[int]log.LogLevel{
|
||||||
func toLogEntry(msg []byte, from string) *log.Entry {
|
func toLogEntry(msg []byte, from string) *log.Entry {
|
||||||
syslogMsg := libSyslog.Parse(msg)
|
syslogMsg := libSyslog.Parse(msg)
|
||||||
|
|
||||||
return &log.Entry{
|
entry := log.NewEntry(nil)
|
||||||
Level: SyslogPriorityMap[syslogMsg.Severity],
|
entry = entry.WithField("hostname", from)
|
||||||
Text: syslogMsg.Content,
|
entry.Time = syslogMsg.Timestemp
|
||||||
Hostname: from,
|
entry.Level = SyslogPriorityMap[syslogMsg.Severity]
|
||||||
}
|
entry.Message = syslogMsg.Content
|
||||||
|
return entry
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package syslog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestToEntry(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
entry := toLogEntry([]byte("<11>Aug 17 11:43:33 Msg"), "::1")
|
||||||
|
assert.Equal("Msg", entry.Message)
|
||||||
|
assert.Equal(log.ErrorLevel, entry.Level)
|
||||||
|
|
||||||
|
hostname, ok := entry.Data["hostname"]
|
||||||
|
assert.True(ok)
|
||||||
|
assert.Equal("::1", hostname)
|
||||||
|
|
||||||
|
}
|
|
@ -3,11 +3,14 @@ package syslog
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/genofire/logmania/lib"
|
"github.com/genofire/logmania/lib"
|
||||||
"github.com/genofire/logmania/log"
|
|
||||||
"github.com/genofire/logmania/receive"
|
"github.com/genofire/logmania/receive"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var logger = log.WithField("receive", "syslog")
|
||||||
|
|
||||||
type Receiver struct {
|
type Receiver struct {
|
||||||
receive.Receiver
|
receive.Receiver
|
||||||
exportChannel chan *log.Entry
|
exportChannel chan *log.Entry
|
||||||
|
@ -19,7 +22,7 @@ func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Rece
|
||||||
ln, err := net.ListenUDP(config.Syslog.Type, addr)
|
ln, err := net.ListenUDP(config.Syslog.Type, addr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("syslog init ", err)
|
logger.Error("init ", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
recv := &Receiver{
|
recv := &Receiver{
|
||||||
|
@ -27,7 +30,7 @@ func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Rece
|
||||||
exportChannel: exportChannel,
|
exportChannel: exportChannel,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("syslog init")
|
logger.Info("init")
|
||||||
|
|
||||||
return recv
|
return recv
|
||||||
}
|
}
|
||||||
|
@ -35,18 +38,21 @@ func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Rece
|
||||||
const maxDataGramSize = 8192
|
const maxDataGramSize = 8192
|
||||||
|
|
||||||
func (rc *Receiver) Listen() {
|
func (rc *Receiver) Listen() {
|
||||||
log.Info("syslog listen")
|
logger.Info("listen")
|
||||||
for {
|
for {
|
||||||
buf := make([]byte, maxDataGramSize)
|
buf := make([]byte, maxDataGramSize)
|
||||||
n, src, err := rc.serverSocket.ReadFromUDP(buf)
|
n, src, err := rc.serverSocket.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("failed to accept connection", err)
|
logger.Warn("failed to accept connection", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
raw := make([]byte, n)
|
raw := make([]byte, n)
|
||||||
copy(raw, buf)
|
copy(raw, buf)
|
||||||
rc.exportChannel <- toLogEntry(raw, src.IP.String())
|
entry := toLogEntry(raw, src.IP.String())
|
||||||
|
if entry != nil {
|
||||||
|
rc.exportChannel <- entry
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue