enabled file logging with log rotation
This commit is contained in:
15
main.go
15
main.go
@@ -30,6 +30,9 @@ var (
|
|||||||
userFromEnv = os.Getenv("USERNAME")
|
userFromEnv = os.Getenv("USERNAME")
|
||||||
passFromEnv = os.Getenv("PASSWORD")
|
passFromEnv = os.Getenv("PASSWORD")
|
||||||
|
|
||||||
|
logFile string
|
||||||
|
enableFileLogging bool
|
||||||
|
|
||||||
//go:embed frontend/dist/index.html
|
//go:embed frontend/dist/index.html
|
||||||
//go:embed frontend/dist/assets/*
|
//go:embed frontend/dist/assets/*
|
||||||
frontend embed.FS
|
frontend embed.FS
|
||||||
@@ -47,6 +50,9 @@ func init() {
|
|||||||
flag.StringVar(&sessionFilePath, "session", ".", "session file path")
|
flag.StringVar(&sessionFilePath, "session", ".", "session file path")
|
||||||
flag.StringVar(&localDatabasePath, "db", "local.db", "local database path")
|
flag.StringVar(&localDatabasePath, "db", "local.db", "local database path")
|
||||||
|
|
||||||
|
flag.BoolVar(&enableFileLogging, "fl", false, "enable outputting logs to a file")
|
||||||
|
flag.StringVar(&logFile, "lf", "yt-dlp-webui.log", "set log file location")
|
||||||
|
|
||||||
flag.BoolVar(&requireAuth, "auth", false, "Enable RPC authentication")
|
flag.BoolVar(&requireAuth, "auth", false, "Enable RPC authentication")
|
||||||
flag.StringVar(&username, "user", userFromEnv, "Username required for auth")
|
flag.StringVar(&username, "user", userFromEnv, "Username required for auth")
|
||||||
flag.StringVar(&password, "pass", passFromEnv, "Password required for auth")
|
flag.StringVar(&password, "pass", passFromEnv, "Password required for auth")
|
||||||
@@ -79,5 +85,12 @@ func main() {
|
|||||||
log.Println(cli.BgRed, "config", cli.Reset, err)
|
log.Println(cli.BgRed, "config", cli.Reset, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
server.RunBlocking(c.Host, c.Port, frontend, localDatabasePath)
|
server.RunBlocking(&server.RunConfig{
|
||||||
|
Host: c.Host,
|
||||||
|
Port: c.Port,
|
||||||
|
App: frontend,
|
||||||
|
DBPath: localDatabasePath,
|
||||||
|
FileLogging: enableFileLogging,
|
||||||
|
LogFile: logFile,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
80
server/logging/file_logger.go
Normal file
80
server/logging/file_logger.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// implements io.Writer interface
|
||||||
|
type LogRotateWriter struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
fd *os.File
|
||||||
|
filename string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRotableLogger(filename string) (*LogRotateWriter, error) {
|
||||||
|
fd, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
w := &LogRotateWriter{filename: filename, fd: fd}
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *LogRotateWriter) Write(b []byte) (int, error) {
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
return w.fd.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *LogRotateWriter) Rotate() error {
|
||||||
|
var err error
|
||||||
|
w.mu.Lock()
|
||||||
|
|
||||||
|
gzFile, err := os.Create(w.filename + "." + time.Now().Format(time.RFC3339) + ".gz")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := io.ReadAll(w.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
w.mu.Unlock()
|
||||||
|
w.gzipLog(gzFile, &data)
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = os.Stat(w.filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.fd != nil {
|
||||||
|
err = w.fd.Close()
|
||||||
|
w.fd = nil
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Remove(w.filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.fd, err = os.Create(w.filename)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *LogRotateWriter) gzipLog(wr io.Writer, data *[]byte) error {
|
||||||
|
if _, err := gzip.NewWriter(wr).Write(*data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -30,6 +30,15 @@ import (
|
|||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RunConfig struct {
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
App fs.FS
|
||||||
|
DBPath string
|
||||||
|
LogFile string
|
||||||
|
FileLogging bool
|
||||||
|
}
|
||||||
|
|
||||||
type serverConfig struct {
|
type serverConfig struct {
|
||||||
frontend fs.FS
|
frontend fs.FS
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
@@ -40,19 +49,37 @@ type serverConfig struct {
|
|||||||
mq *internal.MessageQueue
|
mq *internal.MessageQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunBlocking(host string, port int, frontend fs.FS, dbPath string) {
|
func RunBlocking(cfg *RunConfig) {
|
||||||
var mdb internal.MemoryDB
|
var mdb internal.MemoryDB
|
||||||
|
|
||||||
|
logWriters := []io.Writer{
|
||||||
|
os.Stdout,
|
||||||
|
logging.NewObservableLogger(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.FileLogging {
|
||||||
|
logger, err := logging.NewRotableLogger(cfg.LogFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Hour * 24)
|
||||||
|
logger.Rotate()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
logWriters = append(logWriters, logger)
|
||||||
|
}
|
||||||
|
|
||||||
logger := slog.New(
|
logger := slog.New(
|
||||||
slog.NewTextHandler(
|
slog.NewTextHandler(io.MultiWriter(logWriters...), &slog.HandlerOptions{}),
|
||||||
io.MultiWriter(os.Stdout, logging.NewObservableLogger()),
|
|
||||||
&slog.HandlerOptions{},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
mdb.Restore(logger)
|
mdb.Restore(logger)
|
||||||
|
|
||||||
db, err := sql.Open("sqlite", dbPath)
|
db, err := sql.Open("sqlite", cfg.DBPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed to open database", slog.String("err", err.Error()))
|
logger.Error("failed to open database", slog.String("err", err.Error()))
|
||||||
}
|
}
|
||||||
@@ -66,10 +93,10 @@ func RunBlocking(host string, port int, frontend fs.FS, dbPath string) {
|
|||||||
go mq.Subscriber()
|
go mq.Subscriber()
|
||||||
|
|
||||||
srv := newServer(serverConfig{
|
srv := newServer(serverConfig{
|
||||||
frontend: frontend,
|
frontend: cfg.App,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
host: host,
|
host: cfg.Host,
|
||||||
port: port,
|
port: cfg.Port,
|
||||||
mdb: &mdb,
|
mdb: &mdb,
|
||||||
mq: mq,
|
mq: mq,
|
||||||
db: db,
|
db: db,
|
||||||
@@ -79,11 +106,13 @@ func RunBlocking(host string, port int, frontend fs.FS, dbPath string) {
|
|||||||
go autoPersist(time.Minute*5, &mdb, logger)
|
go autoPersist(time.Minute*5, &mdb, logger)
|
||||||
|
|
||||||
network := "tcp"
|
network := "tcp"
|
||||||
address := fmt.Sprintf("%s:%d", host, port)
|
address := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
|
||||||
if strings.HasPrefix(host, "/") {
|
|
||||||
|
if strings.HasPrefix(cfg.Host, "/") {
|
||||||
network = "unix"
|
network = "unix"
|
||||||
address = host
|
address = cfg.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
listener, err := net.Listen(network, address)
|
listener, err := net.Listen(network, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed to listen", slog.String("err", err.Error()))
|
logger.Error("failed to listen", slog.String("err", err.Error()))
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"io/fs"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func LogRotate() (*os.File, error) {
|
|
||||||
logs := findLogs()
|
|
||||||
|
|
||||||
for _, log := range logs {
|
|
||||||
logfd, err := os.Open(log)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
gzWriter, err := os.Create(log + ".gz")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.Copy(gzWriter, logfd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logfile := time.Now().String() + ".log"
|
|
||||||
config.Instance().CurrentLogFile = logfile
|
|
||||||
|
|
||||||
return os.Create(logfile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func findLogs() []string {
|
|
||||||
var (
|
|
||||||
logfiles []string
|
|
||||||
root = config.Instance().LogPath
|
|
||||||
)
|
|
||||||
|
|
||||||
filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if filepath.Ext(d.Name()) == ".log" {
|
|
||||||
logfiles = append(logfiles, path)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return logfiles
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user