Files
yt-dlp-webui/server/logging/file_logger.go

83 lines
1.4 KiB
Go

package logging
import (
"compress/gzip"
"io"
"log/slog"
"os"
"strings"
"sync"
"time"
)
/*
implements io.Writer interface
File base logger with log-rotate capabilities.
The rotate process must be initiated from an external goroutine.
After rotation the previous logs file are compressed with gzip algorithm.
The rotated log follows this naming: [filename].UTC time.gz
*/
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 {
slog.Info("started log rotation")
w.mu.Lock()
gzFile, err := os.Create(strings.TrimSuffix(w.filename, ".log") + "-" + time.Now().Format(time.RFC3339) + ".log.gz")
if err != nil {
return err
}
zw := gzip.NewWriter(gzFile)
defer func() {
zw.Close()
zw.Flush()
gzFile.Close()
}()
if _, err := os.Stat(w.filename); err != nil {
return err
}
fd, _ := os.Open(w.filename)
io.Copy(zw, fd)
fd.Close()
w.fd.Close()
if err := os.Remove(w.filename); err != nil {
return err
}
w.fd, _ = os.Create(w.filename)
w.mu.Unlock()
slog.Info("ended log rotation")
return err
}