[TASK] improve log with hook
This commit is contained in:
parent
a096771e20
commit
102cf0004f
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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")
|
||||||
|
}
|
|
@ -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")
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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"
|
|
@ -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:]
|
||||||
}
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
[api]
|
||||||
|
|
||||||
|
[database]
|
||||||
|
|
||||||
|
[webserver]
|
||||||
|
enable = true
|
Loading…
Reference in New Issue