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:
WithoutPants
2022-03-17 11:33:59 +11:00
committed by GitHub
parent dcee874f59
commit f69bd8a94f
334 changed files with 1845 additions and 1525 deletions

View File

@@ -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)
}
}