[TASK] improve log with hook

This commit is contained in:
Martin Geno 2017-06-11 03:34:11 +02:00
parent a096771e20
commit 102cf0004f
No known key found for this signature in database
GPG Key ID: F0D39A37E925E941
11 changed files with 266 additions and 52 deletions

57
cmd/logmania/main.go Normal file
View File

@ -0,0 +1,57 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"github.com/genofire/logmania/lib"
"github.com/genofire/logmania/log"
_ "github.com/genofire/logmania/log/hook/output"
)
var (
configPath string
config *lib.Config
)
func main() {
flag.StringVar(&configPath, "config", "logmania.conf", "config file")
log.Info("starting logmania")
config, err := lib.ReadConfig(configPath)
if config == nil || err != nil {
log.Panicf("Could not load '%s' for configuration.", configPath)
}
// Wait for system signal
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGUSR1)
for sig := range sigchan {
switch sig {
case syscall.SIGTERM:
log.Warn("terminated of logmania")
os.Exit(0)
case syscall.SIGQUIT:
quit()
case syscall.SIGHUP:
quit()
case syscall.SIGUSR1:
reload()
}
}
}
func quit() {
log.Info("quit of logmania")
os.Exit(0)
}
func reload() {
log.Info("reload config file")
config, err := lib.ReadConfig(configPath)
if config == nil || err != nil {
log.Errorf("Could not load '%s' for new configuration. Skip reload.", configPath)
return
}
}

View File

@ -1,39 +0,0 @@
package entry
import (
"fmt"
"os"
"time"
)
var TimeFormat = "2006-01-02 15:04:05"
var InternelSend = func(e *Entry) {
format := "%s [%s] %s\n"
v := []interface{}{time.Now().Format(TimeFormat), e.Level.String(), e.Text}
if len(e.Fields) > 0 {
format = "%s [%s] %s (%s)\n"
v = append(v, e.FieldString())
}
text := fmt.Sprintf(format, v...)
if e.Level == PanicLevel {
panic(text)
} else if e.Level > WarnLevel {
os.Stderr.WriteString(text)
} else {
os.Stdout.WriteString(text)
}
}
var FieldOutput = func(fields map[string]interface{}) string {
text := ""
for key, value := range fields {
text = fmt.Sprintf("%s %s=%v", text, key, value)
}
return text[1:]
}
func save(e *Entry) {
InternelSend(e)
}

21
examples/with/main.go Normal file
View File

@ -0,0 +1,21 @@
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/blub", "example")
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")
}

19
examples/without/main.go Normal file
View File

@ -0,0 +1,19 @@
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")
}

34
lib/config.go Normal file
View File

@ -0,0 +1,34 @@
package lib
import (
"io/ioutil"
"github.com/BurntSushi/toml"
"github.com/genofire/logmania/log"
)
type Config struct {
API struct {
Bind string `toml:"bind"`
Interactive bool `toml:"interactive"`
} `toml:"api"`
Database struct {
Type string `toml:"type"`
Connect string `toml:"connect"`
} `toml:"database"`
Webserver struct {
Enable bool `toml:"enable"`
Bind string `toml:"bind"`
} `toml:"webserver"`
}
func ReadConfig(path string) (*Config, error) {
log.Debugf("load of configfile: %s", path)
var config Config
file, _ := ioutil.ReadFile(path)
err := toml.Unmarshal(file, &config)
if err != nil {
return nil, err
}
return &config, nil
}

15
log/hook.go Normal file
View File

@ -0,0 +1,15 @@
package log
type Hook func(e *Entry)
var hooks = make([]Hook, 0)
func AddHook(hook Hook) {
hooks = append(hooks, hook)
}
func save(e *Entry) {
for _, hook := range hooks {
hook(e)
}
}

46
log/hook/client/main.go Normal file
View File

@ -0,0 +1,46 @@
package client
import (
"fmt"
"github.com/gorilla/websocket"
"github.com/genofire/logmania/log"
)
type Logger struct {
AboveLevel log.LogLevel
conn *websocket.Conn
}
func (l *Logger) hook(e *log.Entry) {
if e.Level < l.AboveLevel {
return
}
err := l.conn.WriteJSON(e)
if err != nil {
log.Panic("[logmania] could not send token")
}
}
func (l *Logger) Close() {
l.conn.Close()
}
func Init(url, token string) *Logger {
logger := &Logger{
AboveLevel: log.InfoLevel,
}
c, _, err := websocket.DefaultDialer.Dial(fmt.Sprint(url, "/logger"), nil)
if err != nil {
log.Panic("[logmania] error on connect")
return nil
}
err = c.WriteJSON(token)
if err != nil {
log.Panic("[logmania] could not send token")
return nil
}
logger.conn = c
log.AddHook(logger.hook)
return logger
}

51
log/hook/output/main.go Normal file
View File

@ -0,0 +1,51 @@
package output
import (
"fmt"
"os"
"time"
"github.com/genofire/logmania/log"
)
var (
TimeFormat = "2006-01-02 15:04:05"
ShowTime = true
AboveLevel = log.InfoLevel
)
func hook(e *log.Entry) {
if e.Level < AboveLevel {
return
}
v := []interface{}{}
format := "[%s] %s"
if ShowTime {
format = "%s [%s] %s"
v = append(v, time.Now().Format(TimeFormat))
}
v = append(v, e.Level.String(), e.Text)
if len(e.Fields) > 0 {
v = append(v, e.FieldString())
format = fmt.Sprintf("%s (%%s)\n", format)
} else {
format = fmt.Sprintf("%s\n", format)
}
text := fmt.Sprintf(format, v...)
if e.Level == log.PanicLevel {
panic(text)
} else if e.Level > log.WarnLevel {
os.Stderr.WriteString(text)
} else {
os.Stdout.WriteString(text)
}
}
func init() {
log.AddHook(hook)
}

View File

@ -1,16 +1,16 @@
package entry package log
type logLevel int32 type LogLevel int32
const ( const (
DebugLevel = -1 DebugLevel = LogLevel(-1)
InfoLevel = 0 InfoLevel = LogLevel(0)
WarnLevel = 1 WarnLevel = LogLevel(1)
ErrorLevel = 2 ErrorLevel = LogLevel(2)
PanicLevel = 3 PanicLevel = LogLevel(3)
) )
func (l logLevel) String() string { func (l LogLevel) String() string {
switch l { switch l {
case DebugLevel: case DebugLevel:
return "Debug" return "Debug"

View File

@ -1,19 +1,19 @@
package entry package log
import "fmt" import "fmt"
type Entry struct { type Entry struct {
Level logLevel `json:"level"` Level LogLevel `json:"level"`
Fields map[string]interface{} `json:"fields"` Fields map[string]interface{} `json:"fields"`
Text string `json:"text"` Text string `json:"text"`
} }
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)
} }
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)
@ -35,5 +35,9 @@ func (e *Entry) AddFields(fields map[string]interface{}) *Entry {
} }
func (e *Entry) FieldString() string { func (e *Entry) FieldString() string {
return FieldOutput(e.Fields) text := ""
for key, value := range e.Fields {
text = fmt.Sprintf("%s %s=%v", text, key, value)
}
return text[1:]
} }

6
logmania_example.conf Normal file
View File

@ -0,0 +1,6 @@
[api]
[database]
[webserver]
enable = true