mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 12:54:38 +03:00
Restructure go project (#2356)
* Move main to cmd * Move api to internal * Move logger and manager to internal * Move shell hiding code to separate package * Decouple job from desktop and utils * Decouple session from config * Move static into internal * Decouple config from dlna * Move desktop to internal * Move dlna to internal * Decouple remaining packages from config * Move config into internal * Move jsonschema and paths to models * Make ffmpeg functions private * Move file utility methods into fsutil package * Move symwalk into fsutil * Move single-use util functions into client package * Move slice functions to separate packages * Add env var to suppress windowsgui arg * Move hash functions into separate package * Move identify to internal * Move autotag to internal * Touch UI when generating backend
This commit is contained in:
@@ -1,298 +1,146 @@
|
||||
// Package logger provides methods and interfaces used by other stash packages for logging purposes.
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type LogItem struct {
|
||||
Time time.Time `json:"time"`
|
||||
Type string `json:"type"`
|
||||
Message string `json:"message"`
|
||||
// LoggerImpl is the interface that groups logging methods.
|
||||
//
|
||||
// Progressf logs using a specific progress format.
|
||||
// Trace, Debug, Info, Warn and Error log to the applicable log level. Arguments are handled in the manner of fmt.Print.
|
||||
// Tracef, Debugf, Infof, Warnf, Errorf log to the applicable log level. Arguments are handled in the manner of fmt.Printf.
|
||||
// Fatal and Fatalf log to the applicable log level, then call os.Exit(1).
|
||||
type LoggerImpl interface {
|
||||
Progressf(format string, args ...interface{})
|
||||
|
||||
Trace(args ...interface{})
|
||||
Tracef(format string, args ...interface{})
|
||||
|
||||
Debug(args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
|
||||
Info(args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
|
||||
Warn(args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
|
||||
Error(args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
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
|
||||
customFormatter := new(logrus.TextFormatter)
|
||||
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
||||
customFormatter.ForceColors = true
|
||||
customFormatter.FullTimestamp = true
|
||||
logger.SetOutput(os.Stderr)
|
||||
logger.SetFormatter(customFormatter)
|
||||
|
||||
// #1837 - trigger the console to use color-mode since it won't be
|
||||
// otherwise triggered until the first log entry
|
||||
// this is covers the situation where the logger is only logging to file
|
||||
// and therefore does not trigger the console color-mode - resulting in
|
||||
// the access log colouring not being applied
|
||||
_, _ = customFormatter.Format(logrus.NewEntry(logger))
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
if file != nil {
|
||||
if logOut {
|
||||
// log to file separately disabling colours
|
||||
fileFormatter := new(logrus.TextFormatter)
|
||||
fileFormatter.TimestampFormat = customFormatter.TimestampFormat
|
||||
fileFormatter.FullTimestamp = customFormatter.FullTimestamp
|
||||
logger.AddHook(&fileLogHook{
|
||||
Writer: file,
|
||||
Formatter: fileFormatter,
|
||||
})
|
||||
} else {
|
||||
// logging to file only
|
||||
// turn off the colouring for the file
|
||||
customFormatter.ForceColors = false
|
||||
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
|
||||
|
||||
switch level {
|
||||
case "Debug":
|
||||
ret = logrus.DebugLevel
|
||||
case "Warning":
|
||||
ret = logrus.WarnLevel
|
||||
case "Error":
|
||||
ret = logrus.ErrorLevel
|
||||
case "Trace":
|
||||
ret = logrus.TraceLevel
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
// Logger is the LoggerImpl used when calling the global Logger functions.
|
||||
// It is suggested to use the LoggerImpl interface directly, rather than calling global log functions.
|
||||
var Logger LoggerImpl
|
||||
|
||||
// Progressf calls Progressf with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Progressf(format string, args ...interface{}) {
|
||||
progressLogger.Infof(format, args...)
|
||||
l := &LogItem{
|
||||
Type: "progress",
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
if Logger != nil {
|
||||
Logger.Progressf(format, args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
|
||||
}
|
||||
|
||||
// Trace calls Trace with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Trace(args ...interface{}) {
|
||||
logger.Trace(args...)
|
||||
l := &LogItem{
|
||||
Type: "trace",
|
||||
Message: fmt.Sprint(args...),
|
||||
if Logger != nil {
|
||||
Logger.Trace(args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Tracef calls Tracef with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Tracef(format string, args ...interface{}) {
|
||||
logger.Tracef(format, args...)
|
||||
l := &LogItem{
|
||||
Type: "trace",
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
if Logger != nil {
|
||||
Logger.Tracef(format, args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Debug calls Debug with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Debug(args ...interface{}) {
|
||||
logger.Debug(args...)
|
||||
l := &LogItem{
|
||||
Type: "debug",
|
||||
Message: fmt.Sprint(args...),
|
||||
if Logger != nil {
|
||||
Logger.Debug(args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Debugf calls Debugf with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
logger.Debugf(format, args...)
|
||||
l := &LogItem{
|
||||
Type: "debug",
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
if Logger != nil {
|
||||
Logger.Debugf(format, args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Info calls Info with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Info(args ...interface{}) {
|
||||
logger.Info(args...)
|
||||
l := &LogItem{
|
||||
Type: "info",
|
||||
Message: fmt.Sprint(args...),
|
||||
if Logger != nil {
|
||||
Logger.Info(args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Infof calls Infof with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Infof(format string, args ...interface{}) {
|
||||
logger.Infof(format, args...)
|
||||
l := &LogItem{
|
||||
Type: "info",
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
if Logger != nil {
|
||||
Logger.Infof(format, args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Warn calls Warn with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Warn(args ...interface{}) {
|
||||
logger.Warn(args...)
|
||||
l := &LogItem{
|
||||
Type: "warn",
|
||||
Message: fmt.Sprint(args...),
|
||||
if Logger != nil {
|
||||
Logger.Warn(args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Warnf calls Warnf with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
logger.Warnf(format, args...)
|
||||
l := &LogItem{
|
||||
Type: "warn",
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
if Logger != nil {
|
||||
Logger.Warnf(format, args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Error calls Error with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Error(args ...interface{}) {
|
||||
logger.Error(args...)
|
||||
l := &LogItem{
|
||||
Type: "error",
|
||||
Message: fmt.Sprint(args...),
|
||||
if Logger != nil {
|
||||
Logger.Error(args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Errorf calls Errorf with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
logger.Errorf(format, args...)
|
||||
l := &LogItem{
|
||||
Type: "error",
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
if Logger != nil {
|
||||
Logger.Errorf(format, args...)
|
||||
}
|
||||
addLogItem(l)
|
||||
}
|
||||
|
||||
// Fatal calls Fatal with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Fatal(args ...interface{}) {
|
||||
logger.Fatal(args...)
|
||||
if Logger != nil {
|
||||
Logger.Fatal(args...)
|
||||
} else {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Fatalf calls Fatalf with the Logger registered using RegisterLogger.
|
||||
// If no logger has been registered, then this function is a no-op.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
logger.Fatalf(format, args...)
|
||||
if Logger != nil {
|
||||
Logger.Fatalf(format, args...)
|
||||
} else {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user