mirror of https://github.com/veonik/squirssi
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
3.2 KiB
130 lines
3.2 KiB
package squirssi
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// fileFormatter prints log messages formatted for output in files.
|
|
type fileFormatter struct{}
|
|
|
|
func (f *fileFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|
lvl := ""
|
|
switch entry.Level {
|
|
case logrus.InfoLevel:
|
|
lvl = " INFO"
|
|
case logrus.DebugLevel:
|
|
lvl = "DEBUG"
|
|
case logrus.WarnLevel:
|
|
lvl = " WARN"
|
|
case logrus.ErrorLevel:
|
|
lvl = "ERROR"
|
|
case logrus.FatalLevel:
|
|
lvl = "FATAL"
|
|
case logrus.TraceLevel:
|
|
lvl = "TRACE"
|
|
case logrus.PanicLevel:
|
|
lvl = "PANIC"
|
|
}
|
|
return []byte(fmt.Sprintf("[%s] %s -> %s\n", time.Now().Format("2006-01-02 15:04:05"), lvl, entry.Message)), nil
|
|
}
|
|
|
|
// statusFormatter prints log messages formatted for the StatusWindow.
|
|
type statusFormatter struct {
|
|
levelPadding int
|
|
}
|
|
|
|
func (f *statusFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|
lvl := ""
|
|
switch entry.Level {
|
|
case logrus.InfoLevel:
|
|
lvl = "[ INFO](fg:blue)"
|
|
case logrus.DebugLevel:
|
|
lvl = "[DEBUG](fg:white,bg:blue)"
|
|
case logrus.WarnLevel:
|
|
lvl = "[ WARN](fg:yellow)"
|
|
case logrus.ErrorLevel:
|
|
lvl = "[ERROR](fg:red)"
|
|
case logrus.FatalLevel:
|
|
lvl = "[FATAL](fg:white,bg:red,mod:bold)"
|
|
case logrus.TraceLevel:
|
|
lvl = "[TRACE](fg:white,mod:bold)"
|
|
case logrus.PanicLevel:
|
|
lvl = "[PANIC](fg:white,bg:red,mod:bold)"
|
|
}
|
|
return []byte(fmt.Sprintf(" %s[│](fg:grey) \x030%s\x03", lvl, entry.Message)), nil
|
|
}
|
|
|
|
// logFileWriterHook ensures that log messages are written to some output.
|
|
// This hook writes messages to stdout until Start is called, at which point
|
|
// the hook switches to writing to stderr.
|
|
// Because log messages are routed to the StatusWindow, it's possible for them
|
|
// to get lost if there is a fatal error preventing startup or if a runtime
|
|
// panic occurs.
|
|
type logFileWriterHook struct {
|
|
file *os.File
|
|
fmtr logrus.Formatter
|
|
|
|
started bool
|
|
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
func newLogFileWriterHook() *logFileWriterHook {
|
|
return &logFileWriterHook{file: os.Stdout, fmtr: &fileFormatter{}}
|
|
}
|
|
|
|
func (h *logFileWriterHook) Start() {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
// switch to stderr once started
|
|
h.file = os.Stderr
|
|
h.started = true
|
|
}
|
|
|
|
func (h *logFileWriterHook) Fire(entry *logrus.Entry) error {
|
|
h.mu.RLock()
|
|
defer h.mu.RUnlock()
|
|
if h.started {
|
|
return nil
|
|
}
|
|
fire := func(f *os.File) {
|
|
line, err := h.fmtr.Format(entry)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, "failed to format log message:", err)
|
|
return
|
|
}
|
|
if _, err = f.Write(line); err != nil {
|
|
fmt.Fprintln(os.Stderr, "failed to write log message:", err)
|
|
}
|
|
}
|
|
if h.started {
|
|
// todo: this is dead code, but writing to stderr messes up rendering
|
|
// todo: should this write to a real file instead? need to config such things
|
|
go fire(h.file)
|
|
} else {
|
|
// only block writes if the hook hasn't started yet.
|
|
// this is done assuming that log messages that occur before starting
|
|
// are usually happening right before the application is about to exit,
|
|
// so if we launch a goroutine we risk exiting the process before the
|
|
// write can complete.
|
|
fire(h.file)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *logFileWriterHook) Levels() []logrus.Level {
|
|
return []logrus.Level{
|
|
logrus.PanicLevel,
|
|
logrus.FatalLevel,
|
|
logrus.ErrorLevel,
|
|
logrus.WarnLevel,
|
|
logrus.InfoLevel,
|
|
logrus.DebugLevel,
|
|
}
|
|
}
|