From 992c0eaf022505eafb6afcbe1d547abc71ec4a10 Mon Sep 17 00:00:00 2001 From: Martin Geno Date: Wed, 9 Aug 2017 08:45:45 +0200 Subject: [PATCH] switch architectur --- api/receive/main.go | 92 --------------- api/receive/main_test.go | 1 - cmd/logmania/main.go | 53 ++++----- cmd/logmania/selflog.go | 50 --------- database/app.go | 13 --- database/bootstrap.go | 66 ----------- database/bootstrap_test.go | 1 - database/entry.go | 42 ------- database/user.go | 20 ---- examples/with/main.go | 21 ---- examples/without/main.go | 19 ---- lib/config.go | 26 ++--- lib/doc.go | 2 - lib/http.go | 56 ---------- log/{hook => }/client/main.go | 0 log/{hook => }/client/main_test.go | 0 log/level_test.go | 105 ------------------ log/logger.go | 31 +----- log/logger_test.go | 37 ------ log/main.go | 16 +-- logmania_example.conf | 11 +- notify/all/internal.go | 29 +++-- notify/all/main.go | 1 + {log/hook/output => notify/console}/main.go | 43 +++---- .../output => notify/console}/main_test.go | 16 +-- notify/main.go | 4 +- notify/xmpp/internal.go | 4 +- notify/xmpp/main.go | 13 ++- receive/all/internal.go | 39 +++++++ receive/all/main.go | 5 + receive/main.go | 19 ++++ receive/syslog/internal.go | 35 ++++++ receive/syslog/main.go | 53 +++++++++ 33 files changed, 248 insertions(+), 675 deletions(-) delete mode 100644 api/receive/main.go delete mode 100644 api/receive/main_test.go delete mode 100644 cmd/logmania/selflog.go delete mode 100644 database/app.go delete mode 100644 database/bootstrap.go delete mode 100644 database/bootstrap_test.go delete mode 100644 database/entry.go delete mode 100644 database/user.go delete mode 100644 examples/with/main.go delete mode 100644 examples/without/main.go delete mode 100644 lib/doc.go delete mode 100644 lib/http.go rename log/{hook => }/client/main.go (100%) rename log/{hook => }/client/main_test.go (100%) delete mode 100644 log/level_test.go delete mode 100644 log/logger_test.go rename {log/hook/output => notify/console}/main.go (53%) rename {log/hook/output => notify/console}/main_test.go (72%) create mode 100644 receive/all/internal.go create mode 100644 receive/all/main.go create mode 100644 receive/main.go create mode 100644 receive/syslog/internal.go create mode 100644 receive/syslog/main.go diff --git a/api/receive/main.go b/api/receive/main.go deleted file mode 100644 index ff3e14b..0000000 --- a/api/receive/main.go +++ /dev/null @@ -1,92 +0,0 @@ -// receiver of log entry over network (websocket) -package receive - -import ( - "encoding/json" - "net/http" - - "github.com/gorilla/websocket" - - "github.com/genofire/logmania/database" - "github.com/genofire/logmania/log" - "github.com/genofire/logmania/notify" - - logOutput "github.com/genofire/logmania/log/hook/output" -) - -// http.Handler for init network -type Handler struct { - http.Handler - upgrader websocket.Upgrader - Notify notify.Notifier -} - -// init new Handler -func NewHandler(notifyHandler notify.Notifier) *Handler { - return &Handler{ - upgrader: websocket.Upgrader{}, - Notify: notifyHandler, - } -} - -// server response of handler -func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - logEntry := log.HTTP(r) - c, err := h.upgrader.Upgrade(w, r, nil) - if err != nil { - logEntry.Warn("no webservice upgrade:", err) - return - } - token := "" - defer c.Close() - for { - if token == "" { - var maybeToken string - msgType, msg, err := c.ReadMessage() - if err != nil { - logEntry.Error("receiving token", err) - break - } - if msgType != websocket.TextMessage { - logEntry.Warn("receive no token") - break - } - maybeToken = string(msg) - logEntry.AddField("token", maybeToken) - if !database.IsTokenValid(maybeToken) { - logEntry.Warn("receive wrong token") - break - } else { - token = maybeToken - logEntry.Info("receive valid token") - } - continue - } - var entry log.Entry - msgType, msg, err := c.ReadMessage() - if msgType == -1 { - c.Close() - logEntry.Info("connecting closed") - break - } - if err != nil { - logEntry.Error("receiving log entry:", err) - break - } - err = json.Unmarshal(msg, &entry) - if err != nil { - logEntry.Error("umarshal log entry:", err) - break - } - dbEntry := database.InsertEntry(token, &entry) - if dbEntry != nil && h.Notify != nil { - h.Notify.Send(dbEntry) - } else { - l := logOutput.NewLogger() - e := log.New() - e.Text = "No notifier found" - e.Level = log.WarnLevel - l.Hook(e) - } - } -} diff --git a/api/receive/main_test.go b/api/receive/main_test.go deleted file mode 100644 index 3ccae50..0000000 --- a/api/receive/main_test.go +++ /dev/null @@ -1 +0,0 @@ -package receive diff --git a/cmd/logmania/main.go b/cmd/logmania/main.go index 1b90cca..76b443b 100644 --- a/cmd/logmania/main.go +++ b/cmd/logmania/main.go @@ -15,34 +15,25 @@ import ( "os/signal" "syscall" - "github.com/genofire/logmania/api/receive" - "github.com/genofire/logmania/database" "github.com/genofire/logmania/lib" - "github.com/genofire/logmania/log" - logOutput "github.com/genofire/logmania/log/hook/output" + log "github.com/genofire/logmania/log" "github.com/genofire/logmania/notify" - "github.com/genofire/logmania/notify/all" + allNotify "github.com/genofire/logmania/notify/all" + "github.com/genofire/logmania/receive" + allReceiver "github.com/genofire/logmania/receive/all" ) var ( configPath string config *lib.Config - api *lib.HTTPServer - apiNoPanic *bool notifier notify.Notifier - debug bool + receiver receive.Receiver + logChannel chan *log.Entry ) func main() { flag.StringVar(&configPath, "config", "logmania.conf", "config file") - flag.BoolVar(&debug, "debug", false, "enable debuging") flag.Parse() - logger := NewSelfLogger() - - if debug { - logger.AboveLevel = log.DebugLevel - logOutput.AboveLevel = log.DebugLevel - } log.Info("starting logmania") @@ -51,16 +42,17 @@ func main() { log.Panicf("Could not load '%s' for configuration.", configPath) } - database.Connect(config.Database.Type, config.Database.Connect) - log.AddLogger("selflogger", logger) + notifier = allNotify.Init(&config.Notify) + log.Save = notifier.Send + go func() { + for a := range logChannel { + notifier.Send(a) + } + }() - notifier = all.NotifyInit(&config.Notify) + receiver = allReceiver.Init(&config.Receive, logChannel) - api = &lib.HTTPServer{ - Addr: config.API.Bind, - Handler: receive.NewHandler(notifier), - } - api.Start() + go receiver.Listen() // Wait for system signal sigchan := make(chan os.Signal, 1) @@ -68,7 +60,7 @@ func main() { for sig := range sigchan { switch sig { case syscall.SIGTERM: - log.Warn("terminated of logmania") + log.Panic("terminated of logmania") os.Exit(0) case syscall.SIGQUIT: quit() @@ -81,6 +73,7 @@ func main() { } func quit() { + receiver.Close() notifier.Close() log.Info("quit of logmania") os.Exit(0) @@ -93,10 +86,10 @@ func reload() { log.Errorf("reload: could not load '%s' for new configuration. Skip reload.", configPath) return } - if api.Rebind(config.API.Bind) { - log.Info("reload: new api bind") - } - if database.ReplaceConnect(config.Database.Type, config.Database.Connect) { - log.Info("reload: new database connection establish") - } + receiver.Close() + receiver = allReceiver.Init(&config.Receive, logChannel) + go receiver.Listen() + + notifier.Close() + notifier = allNotify.Init(&config.Notify) } diff --git a/cmd/logmania/selflog.go b/cmd/logmania/selflog.go deleted file mode 100644 index 6ca6d9b..0000000 --- a/cmd/logmania/selflog.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "github.com/genofire/logmania/database" - "github.com/genofire/logmania/log" - - logOutput "github.com/genofire/logmania/log/hook/output" -) - -type SelfLogger struct { - log.Logger - AboveLevel log.LogLevel - lastMsg string - lastTime int -} - -func NewSelfLogger() *SelfLogger { - return &SelfLogger{ - AboveLevel: log.InfoLevel, - } -} - -func (l *SelfLogger) Hook(e *log.Entry) { - if e.Level >= l.AboveLevel { - return - } - // TODO strange logger - if l.lastTime > 15 { - panic("selflogger same log to oftern") - } - if l.lastMsg == e.Text { - l.lastTime += 1 - } else { - l.lastMsg = e.Text - l.lastTime = 1 - } - dbEntry := database.InsertEntry("", e) - if dbEntry != nil && notifier != nil { - notifier.Send(dbEntry) - } else { - l := logOutput.NewLogger() - e := log.New() - e.Text = "No notifier found" - e.Level = log.WarnLevel - l.Hook(e) - } -} - -func (l *SelfLogger) Close() { -} diff --git a/database/app.go b/database/app.go deleted file mode 100644 index abf7518..0000000 --- a/database/app.go +++ /dev/null @@ -1,13 +0,0 @@ -package database - -type Application struct { - ID int `json:"id"` - Name string `json:"name"` - Token string `json:"token"` - //Entries []*Entry `json:"entries" gorm:"-"` -} - -func IsTokenValid(token string) bool { - result := db.Where("token = ?", token).First(&Application{}) - return !result.RecordNotFound() -} diff --git a/database/bootstrap.go b/database/bootstrap.go deleted file mode 100644 index 887167d..0000000 --- a/database/bootstrap.go +++ /dev/null @@ -1,66 +0,0 @@ -package database - -import ( - "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/postgres" - _ "github.com/jinzhu/gorm/dialects/sqlite" - - "github.com/genofire/logmania/log" -) - -var ( - dbType, connect string - db *gorm.DB -) - -func Connect(initDBType, initConnect string) { - var err error - db, err = gorm.Open(initDBType, initConnect) - if err != nil { - log.Panic("failed to connect to database", err) - } - bootstrap() - dbType = initDBType - connect = initConnect -} - -func ReplaceConnect(initDBType, initConnect string) bool { - if dbType == initDBType && connect == initConnect { - return false - } - dbTemp, err := gorm.Open(initDBType, initConnect) - if err != nil { - log.Error("failed to setup new database connection", err) - return false - } - - err = db.Close() - if err != nil { - log.Error("failed to close old database connection", err) - return false - } - db = dbTemp - bootstrap() - dbType = initDBType - connect = initConnect - return true -} - -func bootstrap() { - - var user User - var app Application - db.AutoMigrate(&user) - db.AutoMigrate(&app) - db.AutoMigrate(&Entry{}) - if resultUser := db.First(&user); resultUser.RecordNotFound() { - user.Name = "root" - if resultApp := db.First(app); resultApp.RecordNotFound() { - app.Name = "TestSoftware" - app.Token = "example" - db.Create(&app) - user.Permissions = []Application{app} - } - db.Create(&user) - } -} diff --git a/database/bootstrap_test.go b/database/bootstrap_test.go deleted file mode 100644 index 636bab8..0000000 --- a/database/bootstrap_test.go +++ /dev/null @@ -1 +0,0 @@ -package database diff --git a/database/entry.go b/database/entry.go deleted file mode 100644 index a8ba6fc..0000000 --- a/database/entry.go +++ /dev/null @@ -1,42 +0,0 @@ -package database - -import ( - "encoding/json" - "time" - - "github.com/genofire/logmania/log" -) - -type Entry struct { - ID int `json:"id"` - Time time.Time - ApplicationID int - Fields string `sql:"type:json"` - Text string - Level int -} - -func transformToDB(dbEntry *log.Entry) *Entry { - jsonData, err := json.Marshal(dbEntry.Fields) - if err != nil { - return nil - } - return &Entry{ - Level: int(dbEntry.Level), - Text: dbEntry.Text, - Fields: string(jsonData), - } -} - -func InsertEntry(token string, entryLog *log.Entry) *Entry { - app := Application{} - db.Where("token = ?", token).First(&app) - entry := transformToDB(entryLog) - entry.Time = time.Now() - entry.ApplicationID = app.ID - result := db.Create(&entry) - if result.Error != nil { - log.Error("saving log entry to database", result.Error) - } - return entry -} diff --git a/database/user.go b/database/user.go deleted file mode 100644 index 7712d1b..0000000 --- a/database/user.go +++ /dev/null @@ -1,20 +0,0 @@ -package database - -import "github.com/genofire/logmania/log" - -type User struct { - ID int `json:"id"` - Name string - Mail string - XMPP string - NotifyMail bool - NotifyXMPP bool - NotifyAfterLoglevel log.LogLevel - Permissions []Application `gorm:"many2many:user_permissions;"` -} - -func UserByApplication(id int) []*User { - var users []*User - db.Model(&Application{ID: id}).Related(&users) - return users -} diff --git a/examples/with/main.go b/examples/with/main.go deleted file mode 100644 index 0e49fab..0000000 --- a/examples/with/main.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "time" - - "github.com/genofire/logmania/log" - logClient "github.com/genofire/logmania/log/hook/client" - logOutput "github.com/genofire/logmania/log/hook/output" -) - -func main() { - logClient.Init("ws://localhost:8081", "example", log.DebugLevel) - log.Info("startup") - log.New().AddField("answer", 42).AddFields(map[string]interface{}{"answer": 3, "foo": "bar"}).Warn("Some spezial") - log.Debug("Never shown up") - logOutput.ShowTime = false - logOutput.AboveLevel = log.DebugLevel - log.Debugf("Startup %v", time.Now()) - logOutput.ShowTime = true - log.Panic("let it crash") -} diff --git a/examples/without/main.go b/examples/without/main.go deleted file mode 100644 index c0605bd..0000000 --- a/examples/without/main.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "time" - - "github.com/genofire/logmania/log" - logOutput "github.com/genofire/logmania/log/hook/output" -) - -func main() { - log.Info("startup") - log.New().AddField("answer", 42).AddFields(map[string]interface{}{"answer": 3, "foo": "bar"}).Warn("Some spezial") - log.Debug("Never shown up") - logOutput.ShowTime = false - logOutput.AboveLevel = log.DebugLevel - log.Debugf("Startup %v", time.Now()) - logOutput.ShowTime = true - log.Panic("let it crash") -} diff --git a/lib/config.go b/lib/config.go index efbdbaa..a1d8930 100644 --- a/lib/config.go +++ b/lib/config.go @@ -4,25 +4,15 @@ import ( "io/ioutil" "github.com/BurntSushi/toml" + "github.com/genofire/logmania/log" ) // Struct of the configuration // e.g. under github.com/genofire/logmania/logmania_example.conf type Config struct { - API struct { - Bind string `toml:"bind"` - Interactive bool `toml:"interactive"` - } `toml:"api"` - Notify NotifyConfig `toml:"notify"` - Database struct { - Type string `toml:"type"` - Connect string `toml:"connect"` - } `toml:"database"` - Webserver struct { - Enable bool `toml:"enable"` - Bind string `toml:"bind"` - } `toml:"webserver"` + Notify NotifyConfig `toml:"notify"` + Receive ReceiveConfig `toml:"receive"` } type NotifyConfig struct { @@ -37,11 +27,19 @@ type NotifyConfig struct { StatusMessage string `toml:"status_message"` StartupNotify string `toml:"startup_notify"` } `toml:"xmpp"` + IRC struct { + } `toml:"irc"` +} + +type ReceiveConfig struct { + Syslog struct { + Bind string `toml:"bind"` + } `toml:"syslog"` } // read configuration from a file (use toml as file-format) func ReadConfig(path string) (*Config, error) { - log.Debugf("load of configfile: %s", path) + log.Infof("load of configfile: %s", path) var config Config file, _ := ioutil.ReadFile(path) err := toml.Unmarshal(file, &config) diff --git a/lib/doc.go b/lib/doc.go deleted file mode 100644 index 6876973..0000000 --- a/lib/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// some little goodies for logmania -package lib diff --git a/lib/http.go b/lib/http.go deleted file mode 100644 index e248cdc..0000000 --- a/lib/http.go +++ /dev/null @@ -1,56 +0,0 @@ -package lib - -import ( - "net/http" - "sync" - - "github.com/genofire/logmania/log" -) - -// little httpserver to handle reconnect and http.Handlers -type HTTPServer struct { - srv *http.Server - Addr string - Handler http.Handler - errorNoPanic bool - errorNoPanicAsync sync.Mutex -} - -// start httpserver -func (hs *HTTPServer) Start() { - hs.srv = &http.Server{ - Addr: hs.Addr, - Handler: hs.Handler, - } - go func() { - log.Debug("startup of http listener") - if err := hs.srv.ListenAndServe(); err != nil { - if hs.errorNoPanic { - log.Debug("httpserver shutdown without panic") - return - } - log.Panic(err) - } - }() -} - -// rebind httpserver to a new address (e.g. new configuration) -func (hs *HTTPServer) Rebind(addr string) bool { - if addr == hs.Addr { - return false - } - hs.errorNoPanicAsync.Lock() - hs.errorNoPanic = true - hs.Close() - hs.Addr = addr - hs.Start() - hs.errorNoPanic = false - hs.errorNoPanicAsync.Unlock() - return true -} - -// close/stop current httpserver -func (hs *HTTPServer) Close() { - log.Debug("startup of http listener") - hs.srv.Close() -} diff --git a/log/hook/client/main.go b/log/client/main.go similarity index 100% rename from log/hook/client/main.go rename to log/client/main.go diff --git a/log/hook/client/main_test.go b/log/client/main_test.go similarity index 100% rename from log/hook/client/main_test.go rename to log/client/main_test.go diff --git a/log/level_test.go b/log/level_test.go deleted file mode 100644 index be15444..0000000 --- a/log/level_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package log - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestString(t *testing.T) { - assert := assert.New(t) - - results := map[LogLevel]string{ - DebugLevel: "Debug", - InfoLevel: "Info", - WarnLevel: "Warn", - ErrorLevel: "ERROR", - PanicLevel: "PANIC", - LogLevel(-2): "NOT VALID", - } - - for value, expected := range results { - assert.Equal(expected, value.String()) - } -} - -func TestLogLevelFunc(t *testing.T) { - assert := assert.New(t) - - results := map[LogLevel]func(...interface{}){ - DebugLevel: entry.Debug, - InfoLevel: entry.Info, - WarnLevel: entry.Warn, - ErrorLevel: entry.Error, - } - - for value, function := range results { - function() - assert.Equal(value, entry.Level) - } - assert.Panics(func() { - entry.Panic() - assert.Equal(PanicLevel, entry.Level) - }) -} -func TestLogLevelFormatFunc(t *testing.T) { - assert := assert.New(t) - - results := map[LogLevel]func(string, ...interface{}){ - DebugLevel: entry.Debugf, - InfoLevel: entry.Infof, - WarnLevel: entry.Warnf, - ErrorLevel: entry.Errorf, - } - - for value, function := range results { - function("%.1f", 31.121) - assert.Equal(value, entry.Level) - assert.Equal("31.1", entry.Text) - } - assert.Panics(func() { - entry.Panicf("") - assert.Equal(PanicLevel, entry.Level) - }) -} - -func TestLogLevelInit(t *testing.T) { - assert := assert.New(t) - - results := map[LogLevel]func(...interface{}){ - DebugLevel: Debug, - InfoLevel: Info, - WarnLevel: Warn, - ErrorLevel: Error, - } - - for value, function := range results { - function() - assert.Equal(value, entry.Level) - } - assert.Panics(func() { - Panic() - assert.Equal(PanicLevel, entry.Level) - }) -} - -func TestLogLevelInitFormatFunc(t *testing.T) { - assert := assert.New(t) - - results := map[LogLevel]func(string, ...interface{}){ - DebugLevel: Debugf, - InfoLevel: Infof, - WarnLevel: Warnf, - ErrorLevel: Errorf, - } - - for value, function := range results { - function("%.1f", 31.121) - assert.Equal(value, entry.Level) - assert.Equal("31.1", entry.Text) - } - assert.Panics(func() { - Panicf("") - assert.Equal(PanicLevel, entry.Level) - }) -} diff --git a/log/logger.go b/log/logger.go index 006a525..91f5cbf 100644 --- a/log/logger.go +++ b/log/logger.go @@ -1,32 +1,9 @@ package log -// interface of a logger -type Logger interface { - Hook(*Entry) - Close() -} +type loggerFunc func(*Entry) -var loggers = make(map[string]Logger) +var Save loggerFunc -// bind logger to handle saving/output of a Log entry -func AddLogger(name string, logger Logger) { - if logger != nil { - loggers[name] = logger - } -} -func RemoveLogger(name string) { - loggers[name].Close() - delete(loggers, name) -} - -func save(e *Entry) { - for _, logger := range loggers { - logger.Hook(e) - } - if e.Level == PanicLevel { - for _, logger := range loggers { - logger.Close() - } - panic("panic see last log in logmania") - } +func init() { + Save = func(*Entry) {} } diff --git a/log/logger_test.go b/log/logger_test.go deleted file mode 100644 index 3151fa6..0000000 --- a/log/logger_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package log - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -var entry *Entry - -type SaveLogger struct { - Logger -} - -func (*SaveLogger) Hook(e *Entry) { - entry = e -} -func (*SaveLogger) Close() {} - -func init() { - entry = &Entry{} - AddLogger("name", &SaveLogger{}) -} - -func TestLogger(t *testing.T) { - assert := assert.New(t) - assert.Len(loggers, 1) - - AddLogger("blub", &SaveLogger{}) - assert.Len(loggers, 2) - RemoveLogger("blub") - assert.Len(loggers, 1) - - assert.PanicsWithValue("panic see last log in logmania", func() { - save(&Entry{Level: PanicLevel}) - }) -} diff --git a/log/main.go b/log/main.go index ab6b14f..ed1aa7b 100644 --- a/log/main.go +++ b/log/main.go @@ -5,23 +5,25 @@ import "fmt" // a struct with all information of a log entry type Entry struct { - Level LogLevel `json:"level"` - Fields map[string]interface{} `json:"fields"` - Text string `json:"text"` + 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 +// 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(e) } -// save/out current state of log entry with formation +// 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) + Save(e) } // init new log entry diff --git a/logmania_example.conf b/logmania_example.conf index c34868d..daa4269 100644 --- a/logmania_example.conf +++ b/logmania_example.conf @@ -1,9 +1,2 @@ -[api] -bind = ":8081" - -[database] -type = "sqlite3" -connect = "test.db" - -[webserver] -enable = true +[receive.syslog] +bind = ":10001" diff --git a/notify/all/internal.go b/notify/all/internal.go index d2b2fd9..f5a6d64 100644 --- a/notify/all/internal.go +++ b/notify/all/internal.go @@ -1,17 +1,18 @@ package all import ( - "github.com/genofire/logmania/database" "github.com/genofire/logmania/lib" + "github.com/genofire/logmania/log" "github.com/genofire/logmania/notify" ) type Notifier struct { notify.Notifier - list []notify.Notifier + list []notify.Notifier + channelNotify chan *log.Entry } -func NotifyInit(config *lib.NotifyConfig) notify.Notifier { +func Init(config *lib.NotifyConfig) notify.Notifier { var list []notify.Notifier for _, init := range notify.NotifyRegister { notify := init(config) @@ -21,15 +22,25 @@ func NotifyInit(config *lib.NotifyConfig) notify.Notifier { } list = append(list, notify) } - return &Notifier{ - list: list, + + n := &Notifier{ + list: list, + channelNotify: make(chan *log.Entry), + } + go n.sender() + return n +} + +func (n *Notifier) sender() { + for c := range n.channelNotify { + for _, item := range n.list { + item.Send(c) + } } } -func (n *Notifier) Send(entry *database.Entry) { - for _, item := range n.list { - go item.Send(entry) - } +func (n *Notifier) Send(e *log.Entry) { + n.channelNotify <- e } func (n *Notifier) Close() { diff --git a/notify/all/main.go b/notify/all/main.go index 0c3dec8..7a1e7bc 100644 --- a/notify/all/main.go +++ b/notify/all/main.go @@ -1,5 +1,6 @@ package all import ( + _ "github.com/genofire/logmania/notify/console" _ "github.com/genofire/logmania/notify/xmpp" ) diff --git a/log/hook/output/main.go b/notify/console/main.go similarity index 53% rename from log/hook/output/main.go rename to notify/console/main.go index 16b4ef8..2b83089 100644 --- a/log/hook/output/main.go +++ b/notify/console/main.go @@ -1,6 +1,4 @@ -// logger to print log entry (with color) -// this logger would be bind by importing -package output +package console import ( "fmt" @@ -10,48 +8,38 @@ import ( "github.com/bclicn/color" + "github.com/genofire/logmania/lib" "github.com/genofire/logmania/log" + "github.com/genofire/logmania/notify" ) var ( - TimeFormat = "2006-01-02 15:04:05" - ShowTime = true - AboveLevel = log.InfoLevel - errOutput io.Writer = os.Stderr - output io.Writer = os.Stdout + errOutput io.Writer = os.Stderr + output io.Writer = os.Stdout ) // logger for output -type Logger struct { - log.Logger +type Notifier struct { + notify.Notifier TimeFormat string ShowTime bool - AboveLevel log.LogLevel } -// CurrentLogger (for override settings e.g. AboveLevel,ShowTime or TimeFormat) -var CurrentLogger *Logger - -// create a new output logger -func NewLogger() *Logger { - return &Logger{ +func Init(config *lib.NotifyConfig) notify.Notifier { + return &Notifier{ TimeFormat: "2006-01-02 15:04:05", ShowTime: true, - AboveLevel: log.InfoLevel, } } // handle a log entry (print it on the terminal with color) -func (l *Logger) Hook(e *log.Entry) { - if e.Level < AboveLevel { - return - } +func (n *Notifier) Send(e *log.Entry) { v := []interface{}{} format := "[%s] %s" - if ShowTime { + if n.ShowTime { format = "%s [%s] %s" - v = append(v, color.LightBlue(time.Now().Format(TimeFormat))) + v = append(v, color.LightBlue(time.Now().Format(n.TimeFormat))) } lvl := e.Level.String() switch e.Level { @@ -85,11 +73,8 @@ func (l *Logger) Hook(e *log.Entry) { } } -// do nothing - terminal did not need something to close -func (l *Logger) Close() { -} +func (n *Notifier) Close() {} func init() { - CurrentLogger = NewLogger() - log.AddLogger("output", CurrentLogger) + notify.AddNotifier(Init) } diff --git a/log/hook/output/main_test.go b/notify/console/main_test.go similarity index 72% rename from log/hook/output/main_test.go rename to notify/console/main_test.go index e6dbb26..ca7bb9f 100644 --- a/log/hook/output/main_test.go +++ b/notify/console/main_test.go @@ -1,4 +1,4 @@ -package output +package console import ( "bytes" @@ -27,14 +27,11 @@ func TestOutput(t *testing.T) { out, err := captureOutput(func() { log.Info("test") }) - assert.Regexp("-.*\\[.{5}Info.{4}\\] test", out) assert.Equal("", err) - ShowTime = false out, err = captureOutput(func() { log.Warn("test") }) - assert.Regexp("\\[.{5}Warn.{4}\\] test", out) assert.NotRegexp("-.*\\[.{5}Warn.{4}\\] test", out) assert.Equal("", err) @@ -42,7 +39,6 @@ func TestOutput(t *testing.T) { log.Error("test") }) assert.Equal("", out) - assert.Regexp("\\[.{5}ERROR.{4}\\] test", err) out, err = captureOutput(func() { log.Debug("test") @@ -50,16 +46,6 @@ func TestOutput(t *testing.T) { assert.Equal("", out) assert.Equal("", err) - AboveLevel = log.DebugLevel - - out, err = captureOutput(func() { - log.New().AddField("a", 3).Debug("test") - }) - assert.Regexp("\\[.{5}Debug.{4}\\] test .{8}(a=3)", out) - assert.Equal("", err) - - log.RemoveLogger("output") - out, err = captureOutput(func() { log.Info("test") }) diff --git a/notify/main.go b/notify/main.go index fcb158b..ac23265 100644 --- a/notify/main.go +++ b/notify/main.go @@ -1,14 +1,14 @@ package notify import ( - "github.com/genofire/logmania/database" "github.com/genofire/logmania/lib" + "github.com/genofire/logmania/log" ) var NotifyRegister []NotifyInit type Notifier interface { - Send(entry *database.Entry) + Send(entry *log.Entry) Close() } diff --git a/notify/xmpp/internal.go b/notify/xmpp/internal.go index f108ef7..efa6814 100644 --- a/notify/xmpp/internal.go +++ b/notify/xmpp/internal.go @@ -1,7 +1,7 @@ package xmpp -import "github.com/genofire/logmania/database" +import "github.com/genofire/logmania/log" -func formatEntry(e *database.Entry) string { +func formatEntry(e *log.Entry) string { return e.Text } diff --git a/notify/xmpp/main.go b/notify/xmpp/main.go index c882db9..9626777 100644 --- a/notify/xmpp/main.go +++ b/notify/xmpp/main.go @@ -1,7 +1,6 @@ package xmpp import ( - "github.com/genofire/logmania/database" "github.com/genofire/logmania/lib" "github.com/genofire/logmania/log" "github.com/genofire/logmania/notify" @@ -13,7 +12,7 @@ type Notifier struct { client *xmpp.Client } -func NotifyInit(config *lib.NotifyConfig) notify.Notifier { +func Init(config *lib.NotifyConfig) notify.Notifier { options := xmpp.Options{ Host: config.XMPP.Host, User: config.XMPP.Username, @@ -31,15 +30,17 @@ func NotifyInit(config *lib.NotifyConfig) notify.Notifier { return &Notifier{client: client} } -func (n *Notifier) Send(e *database.Entry) { - users := database.UserByApplication(e.ApplicationID) +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)}) } - } + }*/ } +func (n *Notifier) Close() {} + func init() { - notify.AddNotifier(NotifyInit) + notify.AddNotifier(Init) } diff --git a/receive/all/internal.go b/receive/all/internal.go new file mode 100644 index 0000000..ce774e7 --- /dev/null +++ b/receive/all/internal.go @@ -0,0 +1,39 @@ +package all + +import ( + "github.com/genofire/logmania/lib" + "github.com/genofire/logmania/log" + "github.com/genofire/logmania/receive" +) + +type Receiver struct { + receive.Receiver + list []receive.Receiver +} + +func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Receiver { + var list []receive.Receiver + for _, init := range receive.Register { + receiver := init(config, exportChannel) + + if receiver == nil { + continue + } + list = append(list, receiver) + } + return &Receiver{ + list: list, + } +} + +func (r *Receiver) Listen() { + for _, item := range r.list { + go item.Listen() + } +} + +func (r *Receiver) Close() { + for _, item := range r.list { + item.Close() + } +} diff --git a/receive/all/main.go b/receive/all/main.go new file mode 100644 index 0000000..8d45724 --- /dev/null +++ b/receive/all/main.go @@ -0,0 +1,5 @@ +package all + +import ( + _ "github.com/genofire/logmania/receive/syslog" +) diff --git a/receive/main.go b/receive/main.go new file mode 100644 index 0000000..263cd26 --- /dev/null +++ b/receive/main.go @@ -0,0 +1,19 @@ +package receive + +import ( + "github.com/genofire/logmania/lib" + "github.com/genofire/logmania/log" +) + +var Register = make(map[string]ReceiverInit) + +type Receiver interface { + Listen() + Close() +} + +type ReceiverInit func(*lib.ReceiveConfig, chan *log.Entry) Receiver + +func AddReceiver(name string, n ReceiverInit) { + Register[name] = n +} diff --git a/receive/syslog/internal.go b/receive/syslog/internal.go new file mode 100644 index 0000000..0a483e9 --- /dev/null +++ b/receive/syslog/internal.go @@ -0,0 +1,35 @@ +package syslog + +import "github.com/genofire/logmania/log" + +var SyslogPriorityMap = map[uint]log.LogLevel{ + 0: log.PanicLevel, + 1: log.PanicLevel, + 2: log.PanicLevel, + 3: log.ErrorLevel, + 4: log.WarnLevel, + 5: log.InfoLevel, + 6: log.InfoLevel, + 7: log.DebugLevel, +} + +func toLogEntry(logParts map[string]interface{}) *log.Entry { + severityID := uint(logParts["severity"].(int)) + level := SyslogPriorityMap[severityID] + + if _, ok := logParts["content"]; ok { + return &log.Entry{ + Level: level, + Hostname: logParts["hostname"].(string), + Service: logParts["tag"].(string), + Text: logParts["content"].(string), + } + } + + return &log.Entry{ + Level: level, + Hostname: logParts["hostname"].(string), + Service: logParts["app_name"].(string), + Text: logParts["message"].(string), + } +} diff --git a/receive/syslog/main.go b/receive/syslog/main.go new file mode 100644 index 0000000..19bdde2 --- /dev/null +++ b/receive/syslog/main.go @@ -0,0 +1,53 @@ +package syslog + +import ( + "gopkg.in/mcuadros/go-syslog.v2" + + "github.com/genofire/logmania/lib" + "github.com/genofire/logmania/log" + "github.com/genofire/logmania/receive" +) + +type Receiver struct { + channel syslog.LogPartsChannel + exportChannel chan *log.Entry + server *syslog.Server + receive.Receiver +} + +func Init(config *lib.ReceiveConfig, exportChannel chan *log.Entry) receive.Receiver { + channel := make(syslog.LogPartsChannel) + handler := syslog.NewChannelHandler(channel) + + 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, + exportChannel: exportChannel, + } +} + +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() +} + +func init() { + receive.AddReceiver("syslog", Init) +}