From 032ae1354cc38578486a42f49e97d38ab6927844 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Mon, 16 Dec 2024 22:38:21 +0100 Subject: [PATCH] Add logging to storage package --- server/internal/storage/files.go | 99 +++++++++++++++++++++++++-- server/internal/storage/filesystem.go | 10 +++ server/internal/storage/git.go | 50 +++++++++++++- server/internal/storage/service.go | 12 ++++ server/internal/storage/workspace.go | 16 +++++ 5 files changed, 177 insertions(+), 10 deletions(-) diff --git a/server/internal/storage/files.go b/server/internal/storage/files.go index 51fff58..8d8d781 100644 --- a/server/internal/storage/files.go +++ b/server/internal/storage/files.go @@ -1,5 +1,3 @@ -// Package storage provides functionalities to interact with the file system, -// including listing files, finding files by name, getting file content, saving files, and deleting files. package storage import ( @@ -32,8 +30,22 @@ type FileNode struct { // ListFilesRecursively returns a list of all files in the workspace directory and its subdirectories. // Workspace is identified by the given userID and workspaceID. func (s *Service) ListFilesRecursively(userID, workspaceID int) ([]FileNode, error) { + log := getLogger() + log.Debug("listing files recursively", + "userID", userID, + "workspaceID", workspaceID) + workspacePath := s.GetWorkspacePath(userID, workspaceID) - return s.walkDirectory(workspacePath, "") + nodes, err := s.walkDirectory(workspacePath, "") + if err != nil { + return nil, err + } + + log.Debug("file listing complete", + "userID", userID, + "workspaceID", workspaceID, + "nodeCount", len(nodes)) + return nodes, nil } // walkDirectory recursively walks the directory and returns a list of files and directories. @@ -104,6 +116,12 @@ func (s *Service) walkDirectory(dir, prefix string) ([]FileNode, error) { // Files are searched recursively in the workspace directory and its subdirectories. // Workspace is identified by the given userID and workspaceID. func (s *Service) FindFileByName(userID, workspaceID int, filename string) ([]string, error) { + log := getLogger() + log.Debug("searching for file by name", + "userID", userID, + "workspaceID", workspaceID, + "filename", filename) + var foundPaths []string workspacePath := s.GetWorkspacePath(userID, workspaceID) @@ -131,12 +149,23 @@ func (s *Service) FindFileByName(userID, workspaceID int, filename string) ([]st return nil, fmt.Errorf("file not found") } + log.Debug("file search complete", + "userID", userID, + "workspaceID", workspaceID, + "filename", filename, + "matchCount", len(foundPaths)) return foundPaths, nil } // GetFileContent returns the content of the file at the given filePath. // Path must be a relative path within the workspace directory given by userID and workspaceID. func (s *Service) GetFileContent(userID, workspaceID int, filePath string) ([]byte, error) { + log := getLogger() + log.Debug("reading file content", + "userID", userID, + "workspaceID", workspaceID, + "path", filePath) + fullPath, err := s.ValidatePath(userID, workspaceID, filePath) if err != nil { return nil, err @@ -147,6 +176,13 @@ func (s *Service) GetFileContent(userID, workspaceID int, filePath string) ([]by // SaveFile writes the content to the file at the given filePath. // Path must be a relative path within the workspace directory given by userID and workspaceID. func (s *Service) SaveFile(userID, workspaceID int, filePath string, content []byte) error { + log := getLogger() + log.Debug("saving file", + "userID", userID, + "workspaceID", workspaceID, + "path", filePath, + "contentSize", len(content)) + fullPath, err := s.ValidatePath(userID, workspaceID, filePath) if err != nil { return err @@ -157,17 +193,41 @@ func (s *Service) SaveFile(userID, workspaceID int, filePath string, content []b return err } - return s.fs.WriteFile(fullPath, content, 0644) + if err := s.fs.WriteFile(fullPath, content, 0644); err != nil { + return err + } + + log.Debug("file saved", + "userID", userID, + "workspaceID", workspaceID, + "path", filePath, + "size", len(content)) + return nil } // DeleteFile deletes the file at the given filePath. // Path must be a relative path within the workspace directory given by userID and workspaceID. func (s *Service) DeleteFile(userID, workspaceID int, filePath string) error { + log := getLogger() + log.Debug("deleting file", + "userID", userID, + "workspaceID", workspaceID, + "path", filePath) + fullPath, err := s.ValidatePath(userID, workspaceID, filePath) if err != nil { return err } - return s.fs.Remove(fullPath) + + if err := s.fs.Remove(fullPath); err != nil { + return err + } + + log.Debug("file deleted", + "userID", userID, + "workspaceID", workspaceID, + "path", filePath) + return nil } // FileCountStats holds statistics about files in a workspace @@ -179,6 +239,11 @@ type FileCountStats struct { // GetFileStats returns the total number of files and related statistics in a workspace // Workspace is identified by the given userID and workspaceID func (s *Service) GetFileStats(userID, workspaceID int) (*FileCountStats, error) { + log := getLogger() + log.Debug("gathering file statistics", + "userID", userID, + "workspaceID", workspaceID) + workspacePath := s.GetWorkspacePath(userID, workspaceID) // Check if workspace exists @@ -186,13 +251,33 @@ func (s *Service) GetFileStats(userID, workspaceID int) (*FileCountStats, error) return nil, fmt.Errorf("workspace directory does not exist") } - return s.countFilesInPath(workspacePath) + stats, err := s.countFilesInPath(workspacePath) + if err != nil { + return nil, err + } + log.Debug("file statistics collected", + "userID", userID, + "workspaceID", workspaceID, + "totalFiles", stats.TotalFiles, + "totalSize", stats.TotalSize) + return stats, nil } // GetTotalFileStats returns the total file statistics for the storage. func (s *Service) GetTotalFileStats() (*FileCountStats, error) { - return s.countFilesInPath(s.RootDir) + log := getLogger() + log.Debug("gathering total storage statistics") + + stats, err := s.countFilesInPath(s.RootDir) + if err != nil { + return nil, err + } + + log.Debug("total storage statistics collected", + "totalFiles", stats.TotalFiles, + "totalSize", stats.TotalSize) + return stats, nil } // countFilesInPath counts the total number of files and the total size of files in the given directory. diff --git a/server/internal/storage/filesystem.go b/server/internal/storage/filesystem.go index f5ca0b9..0d6b7b3 100644 --- a/server/internal/storage/filesystem.go +++ b/server/internal/storage/filesystem.go @@ -2,6 +2,7 @@ package storage import ( "io/fs" + "novamd/internal/logging" "os" ) @@ -17,6 +18,15 @@ type fileSystem interface { IsNotExist(err error) bool } +var logger logging.Logger + +func getLogger() logging.Logger { + if logger == nil { + logger = logging.WithGroup("storage") + } + return logger +} + // osFS implements the FileSystem interface using the real filesystem. type osFS struct{} diff --git a/server/internal/storage/git.go b/server/internal/storage/git.go index a4d5d78..c2998b9 100644 --- a/server/internal/storage/git.go +++ b/server/internal/storage/git.go @@ -16,19 +16,37 @@ type RepositoryManager interface { // SetupGitRepo sets up a Git repository for the given userID and workspaceID. // The repository is cloned from the given gitURL using the given gitUser and gitToken. func (s *Service) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken, commitName, commitEmail string) error { + log := getLogger() + log.Info("setting up git repository", + "userID", userID, + "workspaceID", workspaceID, + ) + workspacePath := s.GetWorkspacePath(userID, workspaceID) + if _, ok := s.GitRepos[userID]; !ok { + log.Debug("initializing git repo map for user", + "userID", userID) s.GitRepos[userID] = make(map[int]git.Client) } + s.GitRepos[userID][workspaceID] = s.newGitClient(gitURL, gitUser, gitToken, workspacePath, commitName, commitEmail) + return s.GitRepos[userID][workspaceID].EnsureRepo() } // DisableGitRepo disables the Git repository for the given userID and workspaceID. func (s *Service) DisableGitRepo(userID, workspaceID int) { + log := getLogger() + log.Info("disabling git repository", + "userID", userID, + "workspaceID", workspaceID) + if userRepos, ok := s.GitRepos[userID]; ok { delete(userRepos, workspaceID) if len(userRepos) == 0 { + log.Debug("removing empty user git repos map", + "userID", userID) delete(s.GitRepos, userID) } } @@ -37,6 +55,12 @@ func (s *Service) DisableGitRepo(userID, workspaceID int) { // StageCommitAndPush stages, commit with the message, and pushes the changes to the Git repository. // The git repository belongs to the given userID and is associated with the given workspaceID. func (s *Service) StageCommitAndPush(userID, workspaceID int, message string) (git.CommitHash, error) { + log := getLogger() + log.Debug("preparing to stage, commit and push changes", + "userID", userID, + "workspaceID", workspaceID, + "message", message) + repo, ok := s.getGitRepo(userID, workspaceID) if !ok { return git.CommitHash{}, fmt.Errorf("git settings not configured for this workspace") @@ -47,19 +71,39 @@ func (s *Service) StageCommitAndPush(userID, workspaceID int, message string) (g return git.CommitHash{}, err } - err = repo.Push() - return hash, err + if err = repo.Push(); err != nil { + return hash, err + } + + log.Debug("changes committed and pushed", + "userID", userID, + "workspaceID", workspaceID, + "commitHash", hash.String()) + return hash, nil } // Pull pulls the changes from the remote Git repository. // The git repository belongs to the given userID and is associated with the given workspaceID. func (s *Service) Pull(userID, workspaceID int) error { + log := getLogger() + log.Debug("preparing to pull changes", + "userID", userID, + "workspaceID", workspaceID) + repo, ok := s.getGitRepo(userID, workspaceID) if !ok { return fmt.Errorf("git settings not configured for this workspace") } - return repo.Pull() + err := repo.Pull() + if err != nil { + return err + } + + log.Debug("changes pulled from remote", + "userID", userID, + "workspaceID", workspaceID) + return nil } // getGitRepo returns the Git repository for the given user and workspace IDs. diff --git a/server/internal/storage/service.go b/server/internal/storage/service.go index 07e6b1e..6cc7c15 100644 --- a/server/internal/storage/service.go +++ b/server/internal/storage/service.go @@ -27,6 +27,9 @@ type Options struct { // NewService creates a new Storage instance with the default options and the given rootDir root directory. func NewService(rootDir string) *Service { + getLogger().Debug("creating new storage service", + "rootDir", rootDir, + "options", "default") return NewServiceWithOptions(rootDir, Options{ Fs: &osFS{}, NewGitClient: git.New, @@ -35,14 +38,23 @@ func NewService(rootDir string) *Service { // NewServiceWithOptions creates a new Storage instance with the given options and the given rootDir root directory. func NewServiceWithOptions(rootDir string, options Options) *Service { + log := getLogger() + log.Debug("creating new storage service with custom options", + "rootDir", rootDir) + if options.Fs == nil { + log.Debug("filesystem not provided, using default osFS") options.Fs = &osFS{} } if options.NewGitClient == nil { + log.Debug("git client factory not provided, using default git.New") options.NewGitClient = git.New } + log.Info("storage service created", + "rootDir", rootDir) + return &Service{ fs: options.Fs, newGitClient: options.NewGitClient, diff --git a/server/internal/storage/workspace.go b/server/internal/storage/workspace.go index 560a1b0..564f519 100644 --- a/server/internal/storage/workspace.go +++ b/server/internal/storage/workspace.go @@ -17,6 +17,12 @@ type WorkspaceManager interface { // ValidatePath validates the if the given path is valid within the workspace directory. // Workspace directory is defined as the directory for the given userID and workspaceID. func (s *Service) ValidatePath(userID, workspaceID int, path string) (string, error) { + log := getLogger() + log.Debug("validating path", + "userID", userID, + "workspaceID", workspaceID, + "path", path) + workspacePath := s.GetWorkspacePath(userID, workspaceID) // First check if the path is absolute @@ -43,6 +49,11 @@ func (s *Service) GetWorkspacePath(userID, workspaceID int) string { // InitializeUserWorkspace creates the workspace directory for the given userID and workspaceID. func (s *Service) InitializeUserWorkspace(userID, workspaceID int) error { + log := getLogger() + log.Debug("initializing workspace directory", + "userID", userID, + "workspaceID", workspaceID) + workspacePath := s.GetWorkspacePath(userID, workspaceID) err := s.fs.MkdirAll(workspacePath, 0755) if err != nil { @@ -54,6 +65,11 @@ func (s *Service) InitializeUserWorkspace(userID, workspaceID int) error { // DeleteUserWorkspace deletes the workspace directory for the given userID and workspaceID. func (s *Service) DeleteUserWorkspace(userID, workspaceID int) error { + log := getLogger() + log.Debug("deleting workspace directory", + "userID", userID, + "workspaceID", workspaceID) + workspacePath := s.GetWorkspacePath(userID, workspaceID) err := s.fs.RemoveAll(workspacePath) if err != nil {