syslog reciever complete: sry filter notifier
This commit is contained in:
parent
992c0eaf02
commit
b38f97d97d
|
@ -24,32 +24,38 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
configPath string
|
||||
config *lib.Config
|
||||
notifier notify.Notifier
|
||||
receiver receive.Receiver
|
||||
logChannel chan *log.Entry
|
||||
configPath string
|
||||
config *lib.Config
|
||||
notifyConfig *notify.NotifyState
|
||||
notifier notify.Notifier
|
||||
receiver receive.Receiver
|
||||
logChannel chan *log.Entry
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&configPath, "config", "logmania.conf", "config file")
|
||||
flag.Parse()
|
||||
|
||||
log.Info("starting logmania")
|
||||
|
||||
config, err := lib.ReadConfig(configPath)
|
||||
if config == nil || err != nil {
|
||||
log.Panicf("Could not load '%s' for configuration.", configPath)
|
||||
}
|
||||
|
||||
notifier = allNotify.Init(&config.Notify)
|
||||
notifyConfig := notify.ReadStateFile(config.Notify.StateFile)
|
||||
go notifyConfig.Saver(config.Notify.StateFile)
|
||||
|
||||
notifier = allNotify.Init(&config.Notify, notifyConfig)
|
||||
log.Save = notifier.Send
|
||||
logChannel = make(chan *log.Entry)
|
||||
|
||||
go func() {
|
||||
for a := range logChannel {
|
||||
notifier.Send(a)
|
||||
log.Save(a)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Info("starting logmania")
|
||||
|
||||
receiver = allReceiver.Init(&config.Receive, logChannel)
|
||||
|
||||
go receiver.Listen()
|
||||
|
@ -91,5 +97,5 @@ func reload() {
|
|||
go receiver.Listen()
|
||||
|
||||
notifier.Close()
|
||||
notifier = allNotify.Init(&config.Notify)
|
||||
notifier = allNotify.Init(&config.Notify, notifyConfig)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ type Config struct {
|
|||
}
|
||||
|
||||
type NotifyConfig struct {
|
||||
XMPP struct {
|
||||
StateFile string `toml:"state_file"`
|
||||
XMPP struct {
|
||||
Host string `toml:"host"`
|
||||
Username string `toml:"username"`
|
||||
Password string `toml:"password"`
|
||||
|
@ -33,7 +34,8 @@ type NotifyConfig struct {
|
|||
|
||||
type ReceiveConfig struct {
|
||||
Syslog struct {
|
||||
Bind string `toml:"bind"`
|
||||
Type string `toml:"type"`
|
||||
Address string `toml:"address"`
|
||||
} `toml:"syslog"`
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
package syslog
|
|
@ -1,6 +1,7 @@
|
|||
// logger to bind at github.com/genofire/logmania/log.AddLogger to send log entries to logmania server
|
||||
package client
|
||||
|
||||
/* logger to bind at github.com/genofire/logmania/log.AddLogger to send log entries to logmania server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
|
@ -80,3 +81,4 @@ func Init(url, token string, AboveLevel log.LogLevel) *Logger {
|
|||
log.AddLogger(LOGGER_NAME, CurrentLogger)
|
||||
return CurrentLogger
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
[notify]
|
||||
state_file = "/tmp/logmania.state.json"
|
||||
|
||||
[receive.syslog]
|
||||
bind = ":10001"
|
||||
type = "udp"
|
||||
address = ":10001"
|
||||
|
|
|
@ -12,10 +12,10 @@ type Notifier struct {
|
|||
channelNotify chan *log.Entry
|
||||
}
|
||||
|
||||
func Init(config *lib.NotifyConfig) notify.Notifier {
|
||||
func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
|
||||
var list []notify.Notifier
|
||||
for _, init := range notify.NotifyRegister {
|
||||
notify := init(config)
|
||||
notify := init(config, state)
|
||||
|
||||
if notify == nil {
|
||||
continue
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package notify
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/genofire/logmania/log"
|
||||
)
|
||||
|
||||
type NotifyState struct {
|
||||
Hostname map[string]string `json:"hostname"`
|
||||
HostTo map[string][]string `json:"host_to"`
|
||||
MaxPrioIn map[string]log.LogLevel `json:"maxLevel"`
|
||||
RegexIn map[string][]string `json:"regexIn"`
|
||||
regexIn map[string][]*regexp.Regexp `json:"-"`
|
||||
}
|
||||
|
||||
func (state *NotifyState) SendTo(e *log.Entry) []string {
|
||||
if to, ok := state.HostTo[e.Hostname]; ok {
|
||||
var toList []string
|
||||
for _, toEntry := range to {
|
||||
if lvl := state.MaxPrioIn[toEntry]; e.Level > lvl {
|
||||
continue
|
||||
}
|
||||
toList = append(toList, toEntry)
|
||||
}
|
||||
e.Hostname = state.Hostname[e.Hostname]
|
||||
return toList
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadStateFile(path string) *NotifyState {
|
||||
var state *NotifyState
|
||||
if f, err := os.Open(path); err == nil { // transform data to legacy meshviewer
|
||||
if err = json.NewDecoder(f).Decode(state); err == nil {
|
||||
log.Info("loaded", len(state.HostTo), "nodes")
|
||||
state.regexIn = make(map[string][]*regexp.Regexp)
|
||||
return state
|
||||
} else {
|
||||
log.Error("failed to unmarshal nodes:", err)
|
||||
}
|
||||
} else {
|
||||
log.Error("failed to open state notify file: ", path, ":", err)
|
||||
}
|
||||
return &NotifyState{
|
||||
Hostname: make(map[string]string),
|
||||
HostTo: make(map[string][]string),
|
||||
MaxPrioIn: make(map[string]log.LogLevel),
|
||||
RegexIn: make(map[string][]string),
|
||||
regexIn: make(map[string][]*regexp.Regexp),
|
||||
}
|
||||
}
|
||||
|
||||
func (state *NotifyState) Saver(path string) {
|
||||
c := time.Tick(time.Minute)
|
||||
|
||||
for range c {
|
||||
state.SaveJSON(path)
|
||||
}
|
||||
}
|
||||
|
||||
// SaveJSON to path
|
||||
func (state *NotifyState) SaveJSON(outputFile string) {
|
||||
tmpFile := outputFile + ".tmp"
|
||||
|
||||
f, err := os.OpenFile(tmpFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
err = json.NewEncoder(f).Encode(state)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
f.Close()
|
||||
if err := os.Rename(tmpFile, outputFile); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ type Notifier struct {
|
|||
ShowTime bool
|
||||
}
|
||||
|
||||
func Init(config *lib.NotifyConfig) notify.Notifier {
|
||||
func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
|
||||
return &Notifier{
|
||||
TimeFormat: "2006-01-02 15:04:05",
|
||||
ShowTime: true,
|
||||
|
@ -35,12 +35,17 @@ func Init(config *lib.NotifyConfig) notify.Notifier {
|
|||
// handle a log entry (print it on the terminal with color)
|
||||
func (n *Notifier) Send(e *log.Entry) {
|
||||
v := []interface{}{}
|
||||
format := "[%s] %s"
|
||||
format := "[%s]"
|
||||
|
||||
if n.ShowTime {
|
||||
format = "%s [%s] %s"
|
||||
format = "%s [%s]"
|
||||
v = append(v, color.LightBlue(time.Now().Format(n.TimeFormat)))
|
||||
}
|
||||
if e.Hostname != "" {
|
||||
format = fmt.Sprintf("%s [%%s]", format)
|
||||
v = append(v, color.Purple(e.Hostname))
|
||||
}
|
||||
format = fmt.Sprintf("%s %%s", format)
|
||||
lvl := e.Level.String()
|
||||
switch e.Level {
|
||||
case log.DebugLevel:
|
||||
|
|
|
@ -12,7 +12,7 @@ type Notifier interface {
|
|||
Close()
|
||||
}
|
||||
|
||||
type NotifyInit func(*lib.NotifyConfig) Notifier
|
||||
type NotifyInit func(*lib.NotifyConfig, *NotifyState) Notifier
|
||||
|
||||
func AddNotifier(n NotifyInit) {
|
||||
NotifyRegister = append(NotifyRegister, n)
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package xmpp
|
||||
|
||||
import "github.com/genofire/logmania/log"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/genofire/logmania/log"
|
||||
)
|
||||
|
||||
func formatEntry(e *log.Entry) string {
|
||||
return e.Text
|
||||
return fmt.Sprintf("[%s] [%s] %s", e.Hostname, e.Level, e.Text)
|
||||
}
|
||||
|
|
|
@ -10,9 +10,10 @@ import (
|
|||
type Notifier struct {
|
||||
notify.Notifier
|
||||
client *xmpp.Client
|
||||
state *notify.NotifyState
|
||||
}
|
||||
|
||||
func Init(config *lib.NotifyConfig) notify.Notifier {
|
||||
func Init(config *lib.NotifyConfig, state *notify.NotifyState) notify.Notifier {
|
||||
options := xmpp.Options{
|
||||
Host: config.XMPP.Host,
|
||||
User: config.XMPP.Username,
|
||||
|
@ -27,16 +28,17 @@ func Init(config *lib.NotifyConfig) notify.Notifier {
|
|||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Notifier{client: client}
|
||||
return &Notifier{client: client, state: state}
|
||||
}
|
||||
|
||||
func (n *Notifier) Send(e *log.Entry) {
|
||||
/*users :=
|
||||
for _, user := range users {
|
||||
if user.NotifyXMPP && log.LogLevel(e.Level) >= user.NotifyAfterLoglevel {
|
||||
n.client.SendHtml(xmpp.Chat{Remote: user.XMPP, Type: "chat", Text: formatEntry(e)})
|
||||
}
|
||||
}*/
|
||||
to := n.state.SendTo(e)
|
||||
if to == nil {
|
||||
return
|
||||
}
|
||||
for _, to := range to {
|
||||
n.client.SendHtml(xmpp.Chat{Remote: to, Type: "chat", Text: formatEntry(e)})
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) Close() {}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
package syslog
|
||||
|
||||
import "github.com/genofire/logmania/log"
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
var SyslogPriorityMap = map[uint]log.LogLevel{
|
||||
"github.com/genofire/logmania/log"
|
||||
)
|
||||
|
||||
var SyslogPriorityMap = map[int]log.LogLevel{
|
||||
0: log.PanicLevel,
|
||||
1: log.PanicLevel,
|
||||
2: log.PanicLevel,
|
||||
|
@ -13,23 +18,24 @@ var SyslogPriorityMap = map[uint]log.LogLevel{
|
|||
7: log.DebugLevel,
|
||||
}
|
||||
|
||||
func toLogEntry(logParts map[string]interface{}) *log.Entry {
|
||||
severityID := uint(logParts["severity"].(int))
|
||||
level := SyslogPriorityMap[severityID]
|
||||
func toLogEntry(msg []byte, from string) *log.Entry {
|
||||
re := regexp.MustCompile("<([0-9]*)>(.*)")
|
||||
match := re.FindStringSubmatch(string(msg))
|
||||
|
||||
if _, ok := logParts["content"]; ok {
|
||||
if len(match) <= 1 {
|
||||
return &log.Entry{
|
||||
Level: level,
|
||||
Hostname: logParts["hostname"].(string),
|
||||
Service: logParts["tag"].(string),
|
||||
Text: logParts["content"].(string),
|
||||
Level: log.DebugLevel,
|
||||
Text: string(msg),
|
||||
Hostname: from,
|
||||
}
|
||||
}
|
||||
v, _ := strconv.Atoi(match[1])
|
||||
prio := v % 8
|
||||
text := match[2]
|
||||
|
||||
return &log.Entry{
|
||||
Level: level,
|
||||
Hostname: logParts["hostname"].(string),
|
||||
Service: logParts["app_name"].(string),
|
||||
Text: logParts["message"].(string),
|
||||
Level: SyslogPriorityMap[prio],
|
||||
Text: text,
|
||||
Hostname: from,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package syslog
|
||||
|
||||
import (
|
||||
"gopkg.in/mcuadros/go-syslog.v2"
|
||||
"net"
|
||||
|
||||
"github.com/genofire/logmania/lib"
|
||||
"github.com/genofire/logmania/log"
|
||||
|
@ -9,43 +9,49 @@ import (
|
|||
)
|
||||
|
||||
type Receiver struct {
|
||||
channel syslog.LogPartsChannel
|
||||
exportChannel chan *log.Entry
|
||||
server *syslog.Server
|
||||
receive.Receiver
|
||||
exportChannel chan *log.Entry
|
||||
serverSocket *net.UDPConn
|
||||
}
|
||||
|
||||
func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Receiver {
|
||||
channel := make(syslog.LogPartsChannel)
|
||||
handler := syslog.NewChannelHandler(channel)
|
||||
addr, err := net.ResolveUDPAddr(config.Syslog.Type, config.Syslog.Address)
|
||||
ln, err := net.ListenUDP(config.Syslog.Type, addr)
|
||||
|
||||
server := syslog.NewServer()
|
||||
server.SetFormat(syslog.RFC5424)
|
||||
server.SetHandler(handler)
|
||||
server.ListenUDP(config.Syslog.Bind)
|
||||
|
||||
log.Info("syslog binded to: ", config.Syslog.Bind)
|
||||
|
||||
return &Receiver{
|
||||
channel: channel,
|
||||
server: server,
|
||||
if err != nil {
|
||||
log.Error("syslog init ", err)
|
||||
return nil
|
||||
}
|
||||
recv := &Receiver{
|
||||
serverSocket: ln,
|
||||
exportChannel: exportChannel,
|
||||
}
|
||||
|
||||
log.Info("syslog init")
|
||||
|
||||
return recv
|
||||
}
|
||||
|
||||
const maxDataGramSize = 8192
|
||||
|
||||
func (rc *Receiver) Listen() {
|
||||
log.Info("syslog listen")
|
||||
for {
|
||||
buf := make([]byte, maxDataGramSize)
|
||||
n, src, err := rc.serverSocket.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
log.Warn("failed to accept connection", err)
|
||||
continue
|
||||
}
|
||||
|
||||
raw := make([]byte, n)
|
||||
copy(raw, buf)
|
||||
rc.exportChannel <- toLogEntry(raw, src.IP.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (rc *Receiver) Listen() {
|
||||
rc.server.Boot()
|
||||
log.Info("boot syslog")
|
||||
go func(channel syslog.LogPartsChannel) {
|
||||
for logParts := range channel {
|
||||
rc.exportChannel <- toLogEntry(logParts)
|
||||
}
|
||||
}(rc.channel)
|
||||
}
|
||||
|
||||
func (rc *Receiver) Close() {
|
||||
rc.server.Kill()
|
||||
rc.server.Wait()
|
||||
rc.serverSocket.Close()
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
Loading…
Reference in New Issue