switch architectur

This commit is contained in:
Martin Geno 2017-08-09 08:45:45 +02:00
parent a0b30e6a9c
commit 992c0eaf02
No known key found for this signature in database
GPG Key ID: F0D39A37E925E941
33 changed files with 248 additions and 675 deletions

View File

@ -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)
}
}
}

View File

@ -1 +0,0 @@
package receive

View File

@ -15,34 +15,25 @@ import (
"os/signal" "os/signal"
"syscall" "syscall"
"github.com/genofire/logmania/api/receive"
"github.com/genofire/logmania/database"
"github.com/genofire/logmania/lib" "github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log" log "github.com/genofire/logmania/log"
logOutput "github.com/genofire/logmania/log/hook/output"
"github.com/genofire/logmania/notify" "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 ( var (
configPath string configPath string
config *lib.Config config *lib.Config
api *lib.HTTPServer
apiNoPanic *bool
notifier notify.Notifier notifier notify.Notifier
debug bool receiver receive.Receiver
logChannel chan *log.Entry
) )
func main() { func main() {
flag.StringVar(&configPath, "config", "logmania.conf", "config file") flag.StringVar(&configPath, "config", "logmania.conf", "config file")
flag.BoolVar(&debug, "debug", false, "enable debuging")
flag.Parse() flag.Parse()
logger := NewSelfLogger()
if debug {
logger.AboveLevel = log.DebugLevel
logOutput.AboveLevel = log.DebugLevel
}
log.Info("starting logmania") log.Info("starting logmania")
@ -51,16 +42,17 @@ func main() {
log.Panicf("Could not load '%s' for configuration.", configPath) log.Panicf("Could not load '%s' for configuration.", configPath)
} }
database.Connect(config.Database.Type, config.Database.Connect) notifier = allNotify.Init(&config.Notify)
log.AddLogger("selflogger", logger) 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{ go receiver.Listen()
Addr: config.API.Bind,
Handler: receive.NewHandler(notifier),
}
api.Start()
// Wait for system signal // Wait for system signal
sigchan := make(chan os.Signal, 1) sigchan := make(chan os.Signal, 1)
@ -68,7 +60,7 @@ func main() {
for sig := range sigchan { for sig := range sigchan {
switch sig { switch sig {
case syscall.SIGTERM: case syscall.SIGTERM:
log.Warn("terminated of logmania") log.Panic("terminated of logmania")
os.Exit(0) os.Exit(0)
case syscall.SIGQUIT: case syscall.SIGQUIT:
quit() quit()
@ -81,6 +73,7 @@ func main() {
} }
func quit() { func quit() {
receiver.Close()
notifier.Close() notifier.Close()
log.Info("quit of logmania") log.Info("quit of logmania")
os.Exit(0) os.Exit(0)
@ -93,10 +86,10 @@ func reload() {
log.Errorf("reload: could not load '%s' for new configuration. Skip reload.", configPath) log.Errorf("reload: could not load '%s' for new configuration. Skip reload.", configPath)
return return
} }
if api.Rebind(config.API.Bind) { receiver.Close()
log.Info("reload: new api bind") receiver = allReceiver.Init(&config.Receive, logChannel)
} go receiver.Listen()
if database.ReplaceConnect(config.Database.Type, config.Database.Connect) {
log.Info("reload: new database connection establish") notifier.Close()
} notifier = allNotify.Init(&config.Notify)
} }

View File

@ -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() {
}

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -1 +0,0 @@
package database

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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")
}

View File

@ -4,25 +4,15 @@ import (
"io/ioutil" "io/ioutil"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/genofire/logmania/log" "github.com/genofire/logmania/log"
) )
// Struct of the configuration // Struct of the configuration
// e.g. under github.com/genofire/logmania/logmania_example.conf // e.g. under github.com/genofire/logmania/logmania_example.conf
type Config struct { type Config struct {
API struct { Notify NotifyConfig `toml:"notify"`
Bind string `toml:"bind"` Receive ReceiveConfig `toml:"receive"`
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"`
} }
type NotifyConfig struct { type NotifyConfig struct {
@ -37,11 +27,19 @@ type NotifyConfig struct {
StatusMessage string `toml:"status_message"` StatusMessage string `toml:"status_message"`
StartupNotify string `toml:"startup_notify"` StartupNotify string `toml:"startup_notify"`
} `toml:"xmpp"` } `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) // read configuration from a file (use toml as file-format)
func ReadConfig(path string) (*Config, error) { func ReadConfig(path string) (*Config, error) {
log.Debugf("load of configfile: %s", path) log.Infof("load of configfile: %s", path)
var config Config var config Config
file, _ := ioutil.ReadFile(path) file, _ := ioutil.ReadFile(path)
err := toml.Unmarshal(file, &config) err := toml.Unmarshal(file, &config)

View File

@ -1,2 +0,0 @@
// some little goodies for logmania
package lib

View File

@ -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()
}

View File

@ -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)
})
}

View File

@ -1,32 +1,9 @@
package log package log
// interface of a logger type loggerFunc func(*Entry)
type Logger interface {
Hook(*Entry)
Close()
}
var loggers = make(map[string]Logger) var Save loggerFunc
// bind logger to handle saving/output of a Log entry func init() {
func AddLogger(name string, logger Logger) { Save = func(*Entry) {}
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")
}
} }

View File

@ -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})
})
}

View File

@ -5,23 +5,25 @@ import "fmt"
// a struct with all information of a log entry // a struct with all information of a log entry
type Entry struct { type Entry struct {
Level LogLevel `json:"level"` Level LogLevel `json:"level"`
Fields map[string]interface{} `json:"fields"` Hostname string `json:"hostname"`
Text string `json:"text"` 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{}) { func (e *Entry) Log(level LogLevel, v ...interface{}) {
e.Text = fmt.Sprint(v...) e.Text = fmt.Sprint(v...)
e.Level = level 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{}) { func (e *Entry) Logf(level LogLevel, format string, v ...interface{}) {
e.Text = fmt.Sprintf(format, v...) e.Text = fmt.Sprintf(format, v...)
e.Level = level e.Level = level
save(e) Save(e)
} }
// init new log entry // init new log entry

View File

@ -1,9 +1,2 @@
[api] [receive.syslog]
bind = ":8081" bind = ":10001"
[database]
type = "sqlite3"
connect = "test.db"
[webserver]
enable = true

View File

@ -1,17 +1,18 @@
package all package all
import ( import (
"github.com/genofire/logmania/database"
"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"
) )
type Notifier struct { type Notifier struct {
notify.Notifier 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 var list []notify.Notifier
for _, init := range notify.NotifyRegister { for _, init := range notify.NotifyRegister {
notify := init(config) notify := init(config)
@ -21,15 +22,25 @@ func NotifyInit(config *lib.NotifyConfig) notify.Notifier {
} }
list = append(list, notify) 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) { func (n *Notifier) Send(e *log.Entry) {
for _, item := range n.list { n.channelNotify <- e
go item.Send(entry)
}
} }
func (n *Notifier) Close() { func (n *Notifier) Close() {

View File

@ -1,5 +1,6 @@
package all package all
import ( import (
_ "github.com/genofire/logmania/notify/console"
_ "github.com/genofire/logmania/notify/xmpp" _ "github.com/genofire/logmania/notify/xmpp"
) )

View File

@ -1,6 +1,4 @@
// logger to print log entry (with color) package console
// this logger would be bind by importing
package output
import ( import (
"fmt" "fmt"
@ -10,48 +8,38 @@ import (
"github.com/bclicn/color" "github.com/bclicn/color"
"github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log" "github.com/genofire/logmania/log"
"github.com/genofire/logmania/notify"
) )
var ( var (
TimeFormat = "2006-01-02 15:04:05" errOutput io.Writer = os.Stderr
ShowTime = true output io.Writer = os.Stdout
AboveLevel = log.InfoLevel
errOutput io.Writer = os.Stderr
output io.Writer = os.Stdout
) )
// logger for output // logger for output
type Logger struct { type Notifier struct {
log.Logger notify.Notifier
TimeFormat string TimeFormat string
ShowTime bool ShowTime bool
AboveLevel log.LogLevel
} }
// CurrentLogger (for override settings e.g. AboveLevel,ShowTime or TimeFormat) func Init(config *lib.NotifyConfig) notify.Notifier {
var CurrentLogger *Logger return &Notifier{
// create a new output logger
func NewLogger() *Logger {
return &Logger{
TimeFormat: "2006-01-02 15:04:05", TimeFormat: "2006-01-02 15:04:05",
ShowTime: true, ShowTime: true,
AboveLevel: log.InfoLevel,
} }
} }
// handle a log entry (print it on the terminal with color) // handle a log entry (print it on the terminal with color)
func (l *Logger) Hook(e *log.Entry) { func (n *Notifier) Send(e *log.Entry) {
if e.Level < AboveLevel {
return
}
v := []interface{}{} v := []interface{}{}
format := "[%s] %s" format := "[%s] %s"
if ShowTime { if n.ShowTime {
format = "%s [%s] %s" 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() lvl := e.Level.String()
switch e.Level { switch e.Level {
@ -85,11 +73,8 @@ func (l *Logger) Hook(e *log.Entry) {
} }
} }
// do nothing - terminal did not need something to close func (n *Notifier) Close() {}
func (l *Logger) Close() {
}
func init() { func init() {
CurrentLogger = NewLogger() notify.AddNotifier(Init)
log.AddLogger("output", CurrentLogger)
} }

View File

@ -1,4 +1,4 @@
package output package console
import ( import (
"bytes" "bytes"
@ -27,14 +27,11 @@ func TestOutput(t *testing.T) {
out, err := captureOutput(func() { out, err := captureOutput(func() {
log.Info("test") log.Info("test")
}) })
assert.Regexp("-.*\\[.{5}Info.{4}\\] test", out)
assert.Equal("", err) assert.Equal("", err)
ShowTime = false
out, err = captureOutput(func() { out, err = captureOutput(func() {
log.Warn("test") log.Warn("test")
}) })
assert.Regexp("\\[.{5}Warn.{4}\\] test", out)
assert.NotRegexp("-.*\\[.{5}Warn.{4}\\] test", out) assert.NotRegexp("-.*\\[.{5}Warn.{4}\\] test", out)
assert.Equal("", err) assert.Equal("", err)
@ -42,7 +39,6 @@ func TestOutput(t *testing.T) {
log.Error("test") log.Error("test")
}) })
assert.Equal("", out) assert.Equal("", out)
assert.Regexp("\\[.{5}ERROR.{4}\\] test", err)
out, err = captureOutput(func() { out, err = captureOutput(func() {
log.Debug("test") log.Debug("test")
@ -50,16 +46,6 @@ func TestOutput(t *testing.T) {
assert.Equal("", out) assert.Equal("", out)
assert.Equal("", err) 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() { out, err = captureOutput(func() {
log.Info("test") log.Info("test")
}) })

View File

@ -1,14 +1,14 @@
package notify package notify
import ( import (
"github.com/genofire/logmania/database"
"github.com/genofire/logmania/lib" "github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log"
) )
var NotifyRegister []NotifyInit var NotifyRegister []NotifyInit
type Notifier interface { type Notifier interface {
Send(entry *database.Entry) Send(entry *log.Entry)
Close() Close()
} }

View File

@ -1,7 +1,7 @@
package xmpp 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 return e.Text
} }

View File

@ -1,7 +1,6 @@
package xmpp package xmpp
import ( import (
"github.com/genofire/logmania/database"
"github.com/genofire/logmania/lib" "github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log" "github.com/genofire/logmania/log"
"github.com/genofire/logmania/notify" "github.com/genofire/logmania/notify"
@ -13,7 +12,7 @@ type Notifier struct {
client *xmpp.Client client *xmpp.Client
} }
func NotifyInit(config *lib.NotifyConfig) notify.Notifier { func Init(config *lib.NotifyConfig) notify.Notifier {
options := xmpp.Options{ options := xmpp.Options{
Host: config.XMPP.Host, Host: config.XMPP.Host,
User: config.XMPP.Username, User: config.XMPP.Username,
@ -31,15 +30,17 @@ func NotifyInit(config *lib.NotifyConfig) notify.Notifier {
return &Notifier{client: client} return &Notifier{client: client}
} }
func (n *Notifier) Send(e *database.Entry) { func (n *Notifier) Send(e *log.Entry) {
users := database.UserByApplication(e.ApplicationID) /*users :=
for _, user := range users { for _, user := range users {
if user.NotifyXMPP && log.LogLevel(e.Level) >= user.NotifyAfterLoglevel { if user.NotifyXMPP && log.LogLevel(e.Level) >= user.NotifyAfterLoglevel {
n.client.SendHtml(xmpp.Chat{Remote: user.XMPP, Type: "chat", Text: formatEntry(e)}) n.client.SendHtml(xmpp.Chat{Remote: user.XMPP, Type: "chat", Text: formatEntry(e)})
} }
} }*/
} }
func (n *Notifier) Close() {}
func init() { func init() {
notify.AddNotifier(NotifyInit) notify.AddNotifier(Init)
} }

39
receive/all/internal.go Normal file
View File

@ -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()
}
}

5
receive/all/main.go Normal file
View File

@ -0,0 +1,5 @@
package all
import (
_ "github.com/genofire/logmania/receive/syslog"
)

19
receive/main.go Normal file
View File

@ -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
}

View File

@ -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),
}
}

53
receive/syslog/main.go Normal file
View File

@ -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)
}