mirror of https://github.com/stashapp/stash.git
264 lines
4.7 KiB
Go
264 lines
4.7 KiB
Go
package logger
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type LogItem struct {
|
|
Time time.Time `json:"time"`
|
|
Type string `json:"type"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
var logger = logrus.New()
|
|
var progressLogger = logrus.New()
|
|
|
|
var LogCache []LogItem
|
|
var mutex = &sync.Mutex{}
|
|
var logSubs []chan []LogItem
|
|
var waiting = false
|
|
var lastBroadcast = time.Now()
|
|
var logBuffer []LogItem
|
|
|
|
// Init initialises the logger based on a logging configuration
|
|
func Init(logFile string, logOut bool, logLevel string) {
|
|
var file *os.File
|
|
|
|
if logFile != "" {
|
|
var err error
|
|
file, err = os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
|
|
|
if err != nil {
|
|
fmt.Printf("Could not open '%s' for log output due to error: %s\n", logFile, err.Error())
|
|
logFile = ""
|
|
}
|
|
}
|
|
|
|
if file != nil && logOut {
|
|
mw := io.MultiWriter(os.Stderr, file)
|
|
logger.Out = mw
|
|
} else if file != nil {
|
|
logger.Out = file
|
|
}
|
|
|
|
// otherwise, output to StdErr
|
|
|
|
SetLogLevel(logLevel)
|
|
}
|
|
|
|
func SetLogLevel(level string) {
|
|
logger.Level = logLevelFromString(level)
|
|
}
|
|
|
|
func logLevelFromString(level string) logrus.Level {
|
|
ret := logrus.InfoLevel
|
|
|
|
if level == "Debug" {
|
|
ret = logrus.DebugLevel
|
|
} else if level == "Warning" {
|
|
ret = logrus.WarnLevel
|
|
} else if level == "Error" {
|
|
ret = logrus.ErrorLevel
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func addLogItem(l *LogItem) {
|
|
mutex.Lock()
|
|
l.Time = time.Now()
|
|
LogCache = append([]LogItem{*l}, LogCache...)
|
|
if len(LogCache) > 30 {
|
|
LogCache = LogCache[:len(LogCache)-1]
|
|
}
|
|
mutex.Unlock()
|
|
go broadcastLogItem(l)
|
|
}
|
|
|
|
func GetLogCache() []LogItem {
|
|
mutex.Lock()
|
|
|
|
ret := make([]LogItem, len(LogCache))
|
|
copy(ret, LogCache)
|
|
|
|
mutex.Unlock()
|
|
|
|
return ret
|
|
}
|
|
|
|
func SubscribeToLog(stop chan int) <-chan []LogItem {
|
|
ret := make(chan []LogItem, 100)
|
|
|
|
go func() {
|
|
<-stop
|
|
unsubscribeFromLog(ret)
|
|
}()
|
|
|
|
mutex.Lock()
|
|
logSubs = append(logSubs, ret)
|
|
mutex.Unlock()
|
|
|
|
return ret
|
|
}
|
|
|
|
func unsubscribeFromLog(toRemove chan []LogItem) {
|
|
mutex.Lock()
|
|
for i, c := range logSubs {
|
|
if c == toRemove {
|
|
logSubs = append(logSubs[:i], logSubs[i+1:]...)
|
|
}
|
|
}
|
|
close(toRemove)
|
|
mutex.Unlock()
|
|
}
|
|
|
|
func doBroadcastLogItems() {
|
|
// assumes mutex held
|
|
|
|
for _, c := range logSubs {
|
|
// don't block waiting to broadcast
|
|
select {
|
|
case c <- logBuffer:
|
|
default:
|
|
}
|
|
}
|
|
|
|
logBuffer = nil
|
|
waiting = false
|
|
lastBroadcast = time.Now()
|
|
}
|
|
|
|
func broadcastLogItem(l *LogItem) {
|
|
mutex.Lock()
|
|
|
|
logBuffer = append(logBuffer, *l)
|
|
|
|
// don't send more than once per second
|
|
if !waiting {
|
|
// if last broadcast was under a second ago, wait until a second has
|
|
// passed
|
|
timeSinceBroadcast := time.Since(lastBroadcast)
|
|
if timeSinceBroadcast.Seconds() < 1 {
|
|
waiting = true
|
|
time.AfterFunc(time.Second-timeSinceBroadcast, func() {
|
|
mutex.Lock()
|
|
doBroadcastLogItems()
|
|
mutex.Unlock()
|
|
})
|
|
} else {
|
|
doBroadcastLogItems()
|
|
}
|
|
}
|
|
// if waiting then adding it to the buffer is sufficient
|
|
|
|
mutex.Unlock()
|
|
}
|
|
|
|
func init() {
|
|
progressLogger.SetFormatter(new(ProgressFormatter))
|
|
}
|
|
|
|
func Progressf(format string, args ...interface{}) {
|
|
progressLogger.Infof(format, args...)
|
|
l := &LogItem{
|
|
Type: "progress",
|
|
Message: fmt.Sprintf(format, args...),
|
|
}
|
|
addLogItem(l)
|
|
|
|
}
|
|
|
|
func Trace(args ...interface{}) {
|
|
logger.Trace(args...)
|
|
}
|
|
|
|
func Debug(args ...interface{}) {
|
|
logger.Debug(args...)
|
|
l := &LogItem{
|
|
Type: "debug",
|
|
Message: fmt.Sprint(args...),
|
|
}
|
|
addLogItem(l)
|
|
}
|
|
|
|
func Debugf(format string, args ...interface{}) {
|
|
logger.Debugf(format, args...)
|
|
l := &LogItem{
|
|
Type: "debug",
|
|
Message: fmt.Sprintf(format, args...),
|
|
}
|
|
addLogItem(l)
|
|
}
|
|
|
|
func Info(args ...interface{}) {
|
|
logger.Info(args...)
|
|
l := &LogItem{
|
|
Type: "info",
|
|
Message: fmt.Sprint(args...),
|
|
}
|
|
addLogItem(l)
|
|
}
|
|
|
|
func Infof(format string, args ...interface{}) {
|
|
logger.Infof(format, args...)
|
|
l := &LogItem{
|
|
Type: "info",
|
|
Message: fmt.Sprintf(format, args...),
|
|
}
|
|
addLogItem(l)
|
|
}
|
|
|
|
func Warn(args ...interface{}) {
|
|
logger.Warn(args...)
|
|
l := &LogItem{
|
|
Type: "warn",
|
|
Message: fmt.Sprint(args...),
|
|
}
|
|
addLogItem(l)
|
|
}
|
|
|
|
func Warnf(format string, args ...interface{}) {
|
|
logger.Warnf(format, args...)
|
|
l := &LogItem{
|
|
Type: "warn",
|
|
Message: fmt.Sprintf(format, args...),
|
|
}
|
|
addLogItem(l)
|
|
}
|
|
|
|
func Error(args ...interface{}) {
|
|
logger.Error(args...)
|
|
l := &LogItem{
|
|
Type: "error",
|
|
Message: fmt.Sprint(args...),
|
|
}
|
|
addLogItem(l)
|
|
}
|
|
|
|
func Errorf(format string, args ...interface{}) {
|
|
logger.Errorf(format, args...)
|
|
l := &LogItem{
|
|
Type: "error",
|
|
Message: fmt.Sprintf(format, args...),
|
|
}
|
|
addLogItem(l)
|
|
}
|
|
|
|
func Fatal(args ...interface{}) {
|
|
logger.Fatal(args...)
|
|
}
|
|
|
|
func Fatalf(format string, args ...interface{}) {
|
|
logger.Fatalf(format, args...)
|
|
}
|
|
|
|
//func WithRequest(req *http.Request) *logrus.Entry {
|
|
// return logger.WithFields(RequestFields(req))
|
|
//}
|