From 1b116c21946318e16167ff119dc8cdac6bbdace4 Mon Sep 17 00:00:00 2001 From: Ben Sarmiento Date: Sun, 5 Nov 2023 00:02:22 +0100 Subject: [PATCH] Start to add zap logger everywhere --- cmd/zurg/main.go | 42 ++++++++++++++++++++++++++------- internal/config/load.go | 8 ++++++- internal/config/types.go | 6 ++--- internal/config/v1.go | 17 ++++++++++++++ internal/mount/mount.go | 38 ------------------------------ internal/zfs/fs.go | 21 +++++++++++++++++ internal/zfs/mount.go | 45 ++++++++++++++++++++++++++++++++++++ internal/zfs/object.go | 50 ++++++++++++++++++++++++++++++++++++++++ pkg/logutil/factory.go | 27 ++++++++++++++++++++++ 9 files changed, 204 insertions(+), 50 deletions(-) delete mode 100644 internal/mount/mount.go create mode 100644 internal/zfs/fs.go create mode 100644 internal/zfs/mount.go create mode 100644 internal/zfs/object.go create mode 100644 pkg/logutil/factory.go diff --git a/cmd/zurg/main.go b/cmd/zurg/main.go index 79cedcb..3b4345d 100644 --- a/cmd/zurg/main.go +++ b/cmd/zurg/main.go @@ -3,7 +3,6 @@ package main import ( "context" "fmt" - "log" "net/http" "os" "os/signal" @@ -11,13 +10,17 @@ import ( "time" "github.com/debridmediamanager.com/zurg/internal/config" - "github.com/debridmediamanager.com/zurg/internal/mount" "github.com/debridmediamanager.com/zurg/internal/net" "github.com/debridmediamanager.com/zurg/internal/torrent" + "github.com/debridmediamanager.com/zurg/internal/zfs" + "github.com/debridmediamanager.com/zurg/pkg/logutil" "github.com/hashicorp/golang-lru/v2/expirable" ) func main() { + rlog := logutil.NewLogger() + log := rlog.Named("main") + config, configErr := config.LoadZurgConfig("./config.yml") if configErr != nil { log.Panicf("Config failed to load: %v", configErr) @@ -33,29 +36,52 @@ func main() { addr := fmt.Sprintf(":%s", config.GetPort()) server := &http.Server{Addr: addr, Handler: mux} + mountPoint := config.GetMountPoint() + if _, err := os.Stat(mountPoint); os.IsNotExist(err) { + if err := os.Mkdir(mountPoint, 0755); err != nil { + log.Panicf("Failed to create mount point: %v", err) + } + } + shutdown := make(chan os.Signal, 1) signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM) go func() { - log.Printf("Starting server on %s\n", addr) + defer func() { + if r := recover(); r != nil { + log.Errorf("Server panic: %v\n", r) + } + }() + log.Infof("Starting server on %s\n", addr) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Panicf("Failed to start server: %v", err) } }() - // Start the mount in a goroutine. + // Start the mount in a goroutine with panic recovery. go func() { - if err := mount.Mount(config.GetMountPath()); err != nil { + defer func() { + if r := recover(); r != nil { + log.Errorf("Mount panic: %v\n", r) + } + }() + log.Infof("Mounting on %s\n", mountPoint) + if err := zfs.Mount(mountPoint); err != nil { log.Panicf("Failed to mount: %v", err) } }() <-shutdown - log.Println("zurg signing off...") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - server.Shutdown(ctx) + if err := server.Shutdown(ctx); err != nil { + log.Errorf("Server shutdown error: %v\n", err) + } + if err := zfs.Unmount(mountPoint); err != nil { + log.Errorf("Unmount error: %v\n", err) + } + log.Info("Zurg signing off") } diff --git a/internal/config/load.go b/internal/config/load.go index bd60cb6..c57b04d 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/debridmediamanager.com/zurg/pkg/logutil" "gopkg.in/yaml.v3" ) @@ -19,10 +20,14 @@ type ConfigInterface interface { MeetsConditions(directory, torrentID, torrentName string, fileNames []string) bool GetOnLibraryUpdate() string GetNetworkBufferSize() int - GetMountPath() string + GetMountPoint() string } func LoadZurgConfig(filename string) (ConfigInterface, error) { + rlog := logutil.NewLogger() + log := rlog.Named("config") + + log.Debug("Loading config file", filename) content, err := os.ReadFile(filename) if err != nil { return nil, err @@ -35,6 +40,7 @@ func LoadZurgConfig(filename string) (ConfigInterface, error) { switch initialConfig.Version { case "v1": + log.Debug("Detected config version: v1") return loadV1Config(content) default: diff --git a/internal/config/types.go b/internal/config/types.go index 9fafcd1..0ca050a 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -10,7 +10,7 @@ type ZurgConfig struct { CanRepair bool `yaml:"enable_repair"` OnLibraryUpdate string `yaml:"on_library_update"` NetworkBufferSize int `yaml:"network_buffer_size"` - MountPath string `yaml:"mount_path"` + MountPoint string `yaml:"mount_point"` } func (z *ZurgConfig) GetToken() string { @@ -57,6 +57,6 @@ func (z *ZurgConfig) GetNetworkBufferSize() int { return z.NetworkBufferSize } -func (z *ZurgConfig) GetMountPath() string { - return z.MountPath +func (z *ZurgConfig) GetMountPoint() string { + return z.MountPoint } diff --git a/internal/config/v1.go b/internal/config/v1.go index dd2bf9b..f9f0d55 100644 --- a/internal/config/v1.go +++ b/internal/config/v1.go @@ -5,14 +5,19 @@ import ( "sort" "strings" + "github.com/debridmediamanager.com/zurg/pkg/logutil" "gopkg.in/yaml.v3" ) func loadV1Config(content []byte) (*ZurgConfigV1, error) { + rlog := logutil.NewLogger() + log := rlog.Named("config") + var configV1 ZurgConfigV1 if err := yaml.Unmarshal(content, &configV1); err != nil { return nil, err } + log.Debug("V1 config loaded successfully") return &configV1, nil } @@ -22,9 +27,13 @@ func (z *ZurgConfigV1) GetVersion() string { } func (z *ZurgConfigV1) GetDirectories() []string { + rlog := logutil.NewLogger() + log := rlog.Named("config") + rootDirectories := make([]string, len(z.Directories)) i := 0 for directory := range z.Directories { + log.Debug("Adding to rootDirectories", directory) rootDirectories[i] = directory i++ } @@ -32,6 +41,12 @@ func (z *ZurgConfigV1) GetDirectories() []string { } func (z *ZurgConfigV1) GetGroupMap() map[string][]string { + // Obtain a new sugared logger instance + rlog := logutil.NewLogger() + log := rlog.Named("config") + + log.Debug("Starting to build the group map from directories") + var groupMap = make(map[string][]string) var groupOrderMap = make(map[string]int) // To store GroupOrder for each directory @@ -39,6 +54,7 @@ func (z *ZurgConfigV1) GetGroupMap() map[string][]string { for directory, val := range z.Directories { groupMap[val.Group] = append(groupMap[val.Group], directory) groupOrderMap[directory] = val.GroupOrder + log.Debugf("Added directory to group: %s, group: %s, groupOrder: %d", directory, val.Group, val.GroupOrder) } // Sort the slice based on GroupOrder and then directory name for deterministic order @@ -50,6 +66,7 @@ func (z *ZurgConfigV1) GetGroupMap() map[string][]string { return groupOrderMap[dirs[i]] < groupOrderMap[dirs[j]] }) groupMap[group] = dirs + log.Debugf("Sorted directories within a group: %s, sortedDirectories: %v", group, dirs) } // Return a deep copy of the map diff --git a/internal/mount/mount.go b/internal/mount/mount.go deleted file mode 100644 index 50596c6..0000000 --- a/internal/mount/mount.go +++ /dev/null @@ -1,38 +0,0 @@ -package mount - -import ( - "errors" - "log" - "os" - - "bazil.org/fuse" - "github.com/mdlayher/sdnotify" -) - -func Mount(mountpoint string) error { - n, err := sdnotify.New() - if err != nil && !errors.Is(err, os.ErrNotExist) { - log.Fatalf("failed to open systemd notifier: %v", err) - } - err = n.Notify( - sdnotify.Statusf("service started successfully"), - sdnotify.Ready, - ) - if err != nil { - log.Fatalf("failed to send ready notification: %v", err) - } - return Unmount(mountpoint, n) -} - -func Unmount(mountpoint string, n *sdnotify.Notifier) error { - log.Println("Unmounting...") - err := n.Notify( - sdnotify.Statusf("service stopped successfully"), - sdnotify.Ready, - ) - if err != nil { - log.Fatalf("failed to send stop notification: %v", err) - } - fuse.Unmount(mountpoint) - return nil -} diff --git a/internal/zfs/fs.go b/internal/zfs/fs.go new file mode 100644 index 0000000..e866579 --- /dev/null +++ b/internal/zfs/fs.go @@ -0,0 +1,21 @@ +package zfs + +import ( + "os" + "sync" + + "bazil.org/fuse/fs" +) + +type FS struct { + uid uint32 + gid uint32 + umask os.FileMode + directIO bool + lock sync.RWMutex +} + +// Root returns the root path +func (f *FS) Root() (fs.Node, error) { + return nil, nil +} diff --git a/internal/zfs/mount.go b/internal/zfs/mount.go new file mode 100644 index 0000000..0304d6c --- /dev/null +++ b/internal/zfs/mount.go @@ -0,0 +1,45 @@ +package zfs + +import ( + "os" + + "bazil.org/fuse" + "bazil.org/fuse/fs" + + "golang.org/x/sys/unix" +) + +func Mount(mountpoint string) error { + options := []fuse.MountOption{ + fuse.AllowOther(), + fuse.AllowNonEmptyMount(), + fuse.MaxReadahead(uint32(128 << 10)), + fuse.DefaultPermissions(), + fuse.FSName("zurgfs"), + } + c, err := fuse.Mount(mountpoint, options...) + if err != nil { + return err + } + defer c.Close() + + srv := fs.New(c, nil) + + filesys := &FS{ + uid: uint32(unix.Geteuid()), + gid: uint32(unix.Getegid()), + umask: os.FileMode(0), + } + + // Serve our tree via FUSE. + if err := srv.Serve(filesys); err != nil { + return err + } + + return nil +} + +func Unmount(mountpoint string) error { + fuse.Unmount(mountpoint) + return nil +} diff --git a/internal/zfs/object.go b/internal/zfs/object.go new file mode 100644 index 0000000..aa0fa94 --- /dev/null +++ b/internal/zfs/object.go @@ -0,0 +1,50 @@ +package zfs + +import ( + "context" + + "bazil.org/fuse" + "bazil.org/fuse/fs" + "github.com/debridmediamanager.com/zurg/internal/torrent" +) + +type Object struct { + fs *FS + objectID string +} + +func (o Object) GetObject() (object *torrent.Torrent, err error) { + return nil, nil +} + +func (o Object) Attr(ctx context.Context, attr *fuse.Attr) error { + return nil +} + +func (o Object) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + return nil, nil +} + +func (o Object) Lookup(ctx context.Context, name string) (fs.Node, error) { + return nil, nil +} + +func (o Object) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { + return nil +} + +func (o Object) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { + return nil, nil +} + +func (o Object) Remove(ctx context.Context, req *fuse.RemoveRequest) error { + return nil +} + +func (o Object) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { + return nil, nil +} + +func (o Object) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error { + return nil +} diff --git a/pkg/logutil/factory.go b/pkg/logutil/factory.go new file mode 100644 index 0000000..417ffd9 --- /dev/null +++ b/pkg/logutil/factory.go @@ -0,0 +1,27 @@ +package logutil + +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func NewLogger() *zap.SugaredLogger { + zapConfig := zap.NewDevelopmentConfig() + zapConfig.EncoderConfig = zapcore.EncoderConfig{ + TimeKey: "time", + LevelKey: "level", + NameKey: "logger", + MessageKey: "msg", + CallerKey: "", + StacktraceKey: "", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: zapcore.CapitalColorLevelEncoder, + EncodeTime: zapcore.ISO8601TimeEncoder, + EncodeDuration: zapcore.StringDurationEncoder, + } + logger, _ := zapConfig.Build() + defer logger.Sync() + sugar := logger.Sugar() + + return sugar +}