switch architectur
This commit is contained in:
parent
a0b30e6a9c
commit
992c0eaf02
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package receive
|
|
@ -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 = all.NotifyInit(&config.Notify)
|
||||
|
||||
api = &lib.HTTPServer{
|
||||
Addr: config.API.Bind,
|
||||
Handler: receive.NewHandler(notifier),
|
||||
notifier = allNotify.Init(&config.Notify)
|
||||
log.Save = notifier.Send
|
||||
go func() {
|
||||
for a := range logChannel {
|
||||
notifier.Send(a)
|
||||
}
|
||||
api.Start()
|
||||
}()
|
||||
|
||||
receiver = allReceiver.Init(&config.Receive, logChannel)
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package database
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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"`
|
||||
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)
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
// some little goodies for logmania
|
||||
package lib
|
56
lib/http.go
56
lib/http.go
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
|
@ -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) {}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
})
|
||||
}
|
10
log/main.go
10
log/main.go
|
@ -6,22 +6,24 @@ 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
|
||||
// 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
|
||||
|
|
|
@ -1,9 +1,2 @@
|
|||
[api]
|
||||
bind = ":8081"
|
||||
|
||||
[database]
|
||||
type = "sqlite3"
|
||||
connect = "test.db"
|
||||
|
||||
[webserver]
|
||||
enable = true
|
||||
[receive.syslog]
|
||||
bind = ":10001"
|
||||
|
|
|
@ -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
|
||||
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{
|
||||
|
||||
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() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package all
|
||||
|
||||
import (
|
||||
_ "github.com/genofire/logmania/notify/console"
|
||||
_ "github.com/genofire/logmania/notify/xmpp"
|
||||
)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
|
@ -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")
|
||||
})
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package all
|
||||
|
||||
import (
|
||||
_ "github.com/genofire/logmania/receive/syslog"
|
||||
)
|
|
@ -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
|
||||
}
|
|
@ -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),
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue