Add logging to storage package

This commit is contained in:
2024-12-16 22:38:21 +01:00
parent 03e78c3e6b
commit 032ae1354c
5 changed files with 177 additions and 10 deletions

View File

@@ -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.

View File

@@ -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{}

View File

@@ -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()
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.

View File

@@ -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,

View File

@@ -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 {