From 5e453e234d6a563f0d1b8550e4e5c370a720c2be Mon Sep 17 00:00:00 2001 From: Martin Geno Date: Thu, 17 Aug 2017 21:45:58 +0200 Subject: [PATCH] [TASK] add journald json with udp --- bot/command.go | 2 +- lib/config.go | 5 +++ logmania_example.conf | 5 +++ notify/console/main.go | 7 ++- receive/all/main.go | 1 + receive/journald_json/internal.go | 71 +++++++++++++++++++++++++++++++ receive/journald_json/main.go | 62 +++++++++++++++++++++++++++ 7 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 receive/journald_json/internal.go create mode 100644 receive/journald_json/main.go diff --git a/bot/command.go b/bot/command.go index 1d27870..b468df4 100644 --- a/bot/command.go +++ b/bot/command.go @@ -56,7 +56,7 @@ func (b *Bot) sendRemove(answer func(string), from string, params []string) { if list, ok := b.state.HostTo[host]; ok { delete(list, to) b.state.HostTo[host] = list - answer(fmt.Sprintf("added %s in list of %s", to, host)) + answer(fmt.Sprintf("removed %s in list of %s", to, host)) } else { answer("not found host") } diff --git a/lib/config.go b/lib/config.go index 721db3d..8383ced 100644 --- a/lib/config.go +++ b/lib/config.go @@ -18,6 +18,7 @@ type Config struct { type NotifyConfig struct { StateFile string `toml:"state_file"` AlertCheck Duration `toml:"alert_check"` + Console bool `toml:"debug"` XMPP struct { Host string `toml:"host"` Username string `toml:"username"` @@ -38,6 +39,10 @@ type ReceiveConfig struct { Type string `toml:"type"` Address string `toml:"address"` } `toml:"syslog"` + JournaldJSON struct { + Type string `toml:"type"` + Address string `toml:"address"` + } `toml:"journald_json"` } // read configuration from a file (use toml as file-format) diff --git a/logmania_example.conf b/logmania_example.conf index c9c8d43..df565e0 100644 --- a/logmania_example.conf +++ b/logmania_example.conf @@ -1,6 +1,11 @@ [notify] state_file = "/tmp/logmania.state.json" +debug = true [receive.syslog] type = "udp" address = ":10001" + +[receive.journald_json] +type = "udp" +address = ":10002" diff --git a/notify/console/main.go b/notify/console/main.go index f61e02d..ab12f25 100644 --- a/notify/console/main.go +++ b/notify/console/main.go @@ -25,18 +25,23 @@ 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.Hostname != "" { + if e == nil || n == nil { + return + } + if e.Hostname != "" && !n.Debug { return } v := []interface{}{} diff --git a/receive/all/main.go b/receive/all/main.go index 8d45724..5125274 100644 --- a/receive/all/main.go +++ b/receive/all/main.go @@ -1,5 +1,6 @@ package all import ( + _ "github.com/genofire/logmania/receive/journald_json" _ "github.com/genofire/logmania/receive/syslog" ) diff --git a/receive/journald_json/internal.go b/receive/journald_json/internal.go new file mode 100644 index 0000000..a7218e6 --- /dev/null +++ b/receive/journald_json/internal.go @@ -0,0 +1,71 @@ +package journald_json + +import ( + "encoding/json" + "strconv" + + "github.com/genofire/logmania/log" +) + +type JournalMessage struct { + Cursor string `json:"__CURSOR"` + RealtimeTimestamp string `json:"__REALTIME_TIMESTAMP"` + MonotonicTimestamp string `json:"__MONOTONIC_TIMESTAMP"` + TimestampMonotonic string `json:"TIMESTAMP_MONOTONIC"` + TimestampBoottime string `json:"TIMESTAMP_BOOTTIME"` + SourceMonotonicTimestamp string `json:"_SOURCE_MONOTONIC_TIMESTAMP"` + + UID string `json:"_UID"` + GID string `json:"_GID"` + Transport string `json:"_TRANSPORT"` + + Priority string `json:"PRIORITY"` + SyslogFacility string `json:"SYSLOG_FACILITY"` + SyslogIdentifier string `json:"SYSLOG_IDENTIFIER"` + + SystemdCGroup string `json:"_SYSTEMD_CGROUP"` + SystemdUnit string `json:"_SYSTEMD_UNIT"` + SystemdSlice string `json:"_SYSTEMD_SLICE"` + SystemdInvocationID string `json:"_SYSTEMD_INVOCATION_ID"` + + BootID string `json:"_BOOT_ID"` + MachineID string `json:"_MACHINE_ID"` + Hostname string `json:"_HOSTNAME"` + Message string `json:"MESSAGE"` +} + +var PriorityMap = map[int]log.LogLevel{ + 0: log.PanicLevel, // emerg + 1: log.PanicLevel, // alert + 2: log.PanicLevel, // crit + 3: log.ErrorLevel, // err + 4: log.WarnLevel, // warn + 5: log.InfoLevel, // notice + 6: log.InfoLevel, // info + 7: log.DebugLevel, // debug +} + +func toLogEntry(msg []byte, from string) *log.Entry { + data := &JournalMessage{} + mapEntry := make(map[string]interface{}) + err := json.Unmarshal(msg, data) + if err != nil { + return nil + } + err = json.Unmarshal(msg, mapEntry) + prio, err := strconv.Atoi(data.Priority) + if err != nil { + return nil + } + e := &log.Entry{ + Level: PriorityMap[prio], + Hostname: from, + Service: data.SyslogIdentifier, + Text: data.Message, + Fields: mapEntry, + } + if data.SystemdUnit == "" { + e.Service = data.SystemdUnit + } + return e +} diff --git a/receive/journald_json/main.go b/receive/journald_json/main.go new file mode 100644 index 0000000..696c34d --- /dev/null +++ b/receive/journald_json/main.go @@ -0,0 +1,62 @@ +package journald_json + +import ( + "net" + + "github.com/genofire/logmania/lib" + "github.com/genofire/logmania/log" + "github.com/genofire/logmania/receive" +) + +type Receiver struct { + receive.Receiver + exportChannel chan *log.Entry + serverSocket *net.UDPConn +} + +func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Receiver { + addr, err := net.ResolveUDPAddr(config.JournaldJSON.Type, config.JournaldJSON.Address) + ln, err := net.ListenUDP(config.JournaldJSON.Type, addr) + + if err != nil { + log.Error("journald-json init ", err) + return nil + } + recv := &Receiver{ + serverSocket: ln, + exportChannel: exportChannel, + } + + log.Info("journald-json init") + + return recv +} + +const maxDataGramSize = 8192 + +func (rc *Receiver) Listen() { + log.Info("journald-json 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) + entry := toLogEntry(raw, src.IP.String()) + if entry != nil { + rc.exportChannel <- entry + } + } +} + +func (rc *Receiver) Close() { + rc.serverSocket.Close() +} + +func init() { + receive.AddReceiver("journald_json", Init) +}