func (u *Unpackerr) setupLogging() {
	u.Logger.debug = u.Config.Debug
	if u.Logger.Logger.SetFlags(log.LstdFlags); u.Config.Debug {
		u.Logger.Logger.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
	}
	logFile, err := homedir.Expand(u.Config.LogFile)
	if err != nil {
		logFile = u.Config.LogFile
	}
	u.Config.LogFile = logFile
	rotate := &rotatorr.Config{
		Filepath: u.Config.LogFile,                      
		FileSize: int64(u.Config.LogFileMb) * megabyte,  
		Rotatorr: &timerotator.Layout{
			FileCount:  u.Config.LogFiles,
			PostRotate: u.postLogRotate,
		},  
		DirMode: logsDirMode,
	}
	var writer io.Writer
	switch {  
	case !u.Config.Quiet && u.Config.LogFile != "":
		u.rotatorr = rotatorr.NewMust(rotate)
		writer = io.MultiWriter(u.rotatorr, os.Stdout)
		log.SetOutput(writer)
	case !u.Config.Quiet && u.Config.LogFile == "":
		writer = os.Stdout
	case u.Config.LogFile == "":
		writer = ioutil.Discard  
	default:
		u.rotatorr = rotatorr.NewMust(rotate)
		writer = u.rotatorr
		log.SetOutput(writer)
	}
	u.Logger.Logger.SetOutput(writer)
	u.postLogRotate("", "")
}
setupLogging splits log write into a file and/or stdout.
package unpackerr
import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	homedir "github.com/mitchellh/go-homedir"
	"golift.io/rotatorr"
	"golift.io/rotatorr/timerotator"
)
const (
	callDepth   = 2  
	megabyte    = 1024 * 1024
	logsDirMode = 0o755
)
type ExtractStatus uint8
const (
	WAITING = ExtractStatus(iota)
	QUEUED
	EXTRACTING
	EXTRACTFAILED
	EXTRACTED
	IMPORTED
	DELETING
	DELETEFAILED  
	DELETED
)
func (status ExtractStatus) Desc() string {
	if status > DELETED {
		return "Unknown"
	}
	return []string{
		"Waiting, pre-Queue",
		"Queued",
		"Extracting",
		"Extraction Failed",
		"Extracted, Awaiting Import",
		"Imported",
		"Deleting",
		"Delete Failed",
		"Deleted",
	}[status]
}
func (status ExtractStatus) MarshalText() ([]byte, error) {
	return []byte(status.String()), nil
}
func (status ExtractStatus) String() string {
	if status > DELETED {
		return "unknown"
	}
	return []string{
		"waiting",
		"queued",
		"extracting",
		"extractfailed",
		"extracted",
		"imported",
		"deleting",
		"deletefailed",
		"deleted",
	}[status]
}
func (l *Logger) Debugf(msg string, v ...interface{}) {
	if l.debug {
		err := l.Logger.Output(callDepth, "[DEBUG] "+fmt.Sprintf(msg, v...))
		if err != nil {
			fmt.Println("Logger Error:", err)  
		}
	}
}
func (l *Logger) Print(v ...interface{}) {
	err := l.Logger.Output(callDepth, fmt.Sprintln(v...))
	if err != nil {
		fmt.Println("Logger Error:", err)  
	}
}
func (l *Logger) Printf(msg string, v ...interface{}) {
	err := l.Logger.Output(callDepth, fmt.Sprintf(msg, v...))
	if err != nil {
		fmt.Println("Logger Error:", err)  
	}
}
func (u *Unpackerr) logCurrentQueue() {
	var (
		waiting          uint
		queued           uint
		extracting       uint
		failed           uint
		extracted        uint
		imported         uint
		deleted          uint
		hookOK, hookFail = u.WebhookCounts()
	)
	for name := range u.Map {
		switch u.Map[name].Status {
		case WAITING:
			waiting++
		case QUEUED:
			queued++
		case EXTRACTING:
			extracting++
		case DELETEFAILED, EXTRACTFAILED:
			failed++
		case EXTRACTED:
			extracted++
		case DELETED, DELETING:
			deleted++
		case IMPORTED:
			imported++
		}
	}
	u.Printf("[Unpackerr] Queue: [%d waiting] [%d queued] [%d extracting] [%d extracted] [%d imported]"+
		" [%d failed] [%d deleted]", waiting, queued, extracting, extracted, imported, failed, deleted)
	u.Printf("[Unpackerr] Totals: [%d retries] [%d finished] [%d|%d webhooks] [%d stacks]",
		u.Retries, u.Finished, hookOK, hookFail, len(u.folders.Events)+len(u.updates)+len(u.folders.Updates))
	u.updateTray(u.Retries, u.Finished, waiting, queued, extracting, failed, extracted, imported, deleted,
		hookOK, hookFail, uint(len(u.folders.Events)+len(u.updates)+len(u.folders.Updates)))
}