diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e7f7beb --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,103 @@ +# AGENTS.md + +## Project Overview + +**ginx** is a lightweight Go CLI tool that monitors remote Git repositories for changes and executes custom commands when updates are detected. Built for automating deployments, tasks, and workflows. + +- **Module:** `github.com/didactiklabs/ginx` +- **Go version:** 1.23.3 +- **License:** MIT +- **Current version:** v0.0.7 + +## Tech Stack + +| Component | Technology | +|---|---| +| Language | Go 1.23.3 | +| CLI framework | `github.com/spf13/cobra` v1.8.1 | +| Git operations | `github.com/go-git/go-git/v5` v5.13.2 | +| Logging | `go.uber.org/zap` v1.27.0 | +| Release/Build | GoReleaser v2 | +| CI/CD | GitHub Actions | +| Linting | gofumpt + golines (max 140 chars) | + +## Directory Structure + +``` +. +├── main.go # Entry point +├── go.mod / go.sum # Go module files +├── cmd/ +│ └── root.go # Cobra CLI command definitions +├── internal/ +│ └── utils/ +│ ├── git.go # Git clone, pull, commit checking +│ └── zap.go # Logger initialization +├── scripts/ +│ └── gen_doc.go # CLI doc generator +├── docs/ +│ └── ginx.md # Auto-generated CLI docs +├── public/ +│ └── ginx.png # Project logo +└── .github/ + ├── workflows/ + │ ├── linting.yaml # Lint on PRs + │ ├── unittest.yaml # Tests on push/PR to main + │ ├── build.yaml # GoReleaser dry run on PRs + │ └── release.yaml # GoReleaser release on tag push + ├── dependabot.yml + └── release.yml +``` + +## Commands + +```bash +# Build +go build -o ginx ./ + +# Run +go run ./ --source -b -n -- + +# Test +go test -coverprofile=coverage.out ./... + +# Lint (must pass CI) +gofumpt -d . +golines --max-len=140 . --dry-run + +# Generate CLI docs +go run ./scripts/gen_doc.go + +# GoReleaser dry run +goreleaser release --snapshot +``` + +## Code Conventions + +- **Formatting:** `gofumpt` (stricter than gofmt), max line length 140 via `golines` +- **Package layout:** `main.go` at root, cobra commands in `cmd/`, shared utilities in `internal/utils/` +- **Naming:** Flag vars use camelCase with `Flag` suffix (e.g., `sourceFlag`). Exported types/funcs use PascalCase. +- **Error handling:** Fatal errors use `utils.Logger.Fatal(...)`. Non-fatal use `utils.Logger.Error(...)`. Clean up temp dirs with `os.RemoveAll(dir)` on error paths. +- **Logging:** Structured JSON via zap. Levels: debug, info, error. Set via `--log-level` flag. +- **No comments** in code unless explicitly requested. +- **No emojis** in code or docs unless explicitly requested. + +## Branch & Commit Conventions + +- **Branches:** `feat/`, `fix/`, `chore/` +- **Commits:** Emoji-prefixed format, e.g., `feat : description`, `fix : description`, `chore : description` + +## Architecture Notes + +1. **Flow:** Create temp dir → clone remote repo → poll at interval → compare remote/local commits → pull + run command on change. +2. **`internal/utils/git.go`:** Pure Go git via `go-git`. Functions: `IsRepoCloned`, `CloneRepo`, `PullRepo`, `RunCommand`, `GetLatestRemoteCommit`, `GetLatestLocalCommit`. +3. **`internal/utils/zap.go`:** Exports a global `Logger` variable initialized in `cmd/root.go`'s `PersistentPreRun`. +4. **Version injection:** `cmd.version` set via ldflags at build time by GoReleaser. + +## Known Gaps + +- No test files (`*_test.go`) exist despite CI running `go test`. +- No `.gitignore` file. +- No Makefile or Dockerfile. +- `IsRepoCloned` only checks directory existence, not git validity. +- Temp dir cleanup lacks defer-based safety for unexpected process termination. diff --git a/cmd/root.go b/cmd/root.go index 64aa11c..d4cd47b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,10 +1,13 @@ package cmd import ( + "context" "fmt" "os" + "os/signal" "path" "strings" + "syscall" "time" "github.com/go-git/go-git/v5" @@ -29,145 +32,137 @@ var ( var RootCmd = &cobra.Command{ Use: "ginx [flags] -- ", Short: "ginx", - Long: ` -Ginx is a cli tool that watch a remote repository and run an arbitrary command on changes/updates. -`, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - // Initialize configuration here + Long: `Ginx is a cli tool that watch a remote repository and run an arbitrary command on changes/updates.`, + PersistentPreRun: func(_ *cobra.Command, _ []string) { initConfig() }, - Run: func(cmd *cobra.Command, args []string) { - if versionFlag { - fmt.Printf("%s", version) - os.Exit(0) + Run: run, + Args: cobra.ArbitraryArgs, +} + +func run(_ *cobra.Command, args []string) { + defer utils.SyncLogger() + + if versionFlag { + fmt.Printf("%s", version) + return + } + + source := sourceFlag + branch := branchFlag + interval := time.Duration(pollIntervalFlag) * time.Second + projectName := path.Base(strings.TrimSuffix(source, "/")) + + dir, err := os.MkdirTemp("", fmt.Sprintf("ginx-%s-*", projectName)) + if err != nil { + utils.Logger.Fatal("Failed to create temporary directory.", zap.Error(err)) + } + defer os.RemoveAll(dir) + + r, err := initRepo(source, branch, dir) + if err != nil { + utils.Logger.Fatal("Failed to initialize repository.", zap.Error(err)) + } + + if nowFlag { + runOnce(args, dir) + return + } + + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer stop() + + poll(ctx, r, source, branch, dir, args, interval) +} + +func initRepo(source, branch, dir string) (*git.Repository, error) { + if !utils.IsRepoCloned(source) { + utils.Logger.Info("Cloning repository.", zap.String("url", source), zap.String("branch", branch)) + return utils.CloneRepo(source, branch, dir) + } + utils.Logger.Info("Repository already exists, opening directory.", zap.String("directory", dir)) + return git.PlainOpen(dir) +} + +func runOnce(args []string, dir string) { + if len(args) == 0 { + return + } + utils.Logger.Info("Running command.", zap.String("command", args[0]), zap.Any("args", args[1:])) + if err := utils.RunCommand(dir, args[0], args[1:]...); err != nil { + utils.Logger.Error("Failed to run command.", zap.Error(err)) + } +} + +func poll( + ctx context.Context, + r *git.Repository, + source, branch, dir string, + args []string, + interval time.Duration, +) { + for { + select { + case <-ctx.Done(): + utils.Logger.Info("Shutdown signal received, exiting.") + return + default: } - var r *git.Repository - var err error - source := sourceFlag - branch := branchFlag - interval := time.Duration(pollIntervalFlag) * time.Second - projectName := path.Base(strings.TrimSuffix(source, "/")) - dir, err := os.MkdirTemp("", fmt.Sprintf("ginx-%s-*", projectName)) + remoteCommit, err := utils.GetLatestRemoteCommit(r, branch) if err != nil { - utils.Logger.Fatal("Failed to create temporary directory.", zap.Error(err)) + utils.Logger.Fatal("Error fetching remote commit.", zap.Error(err)) } + utils.Logger.Debug("Fetched remote commit.", zap.String("remoteCommit", remoteCommit)) - if !utils.IsRepoCloned(source) { - utils.Logger.Info("Cloning repository.", zap.String("url", source), zap.String("branch", branch)) - r, err = utils.CloneRepo(source, branch, dir) - if err != nil { - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - utils.Logger.Fatal("Failed to clone repository.", zap.Error(err)) - } - } else { - r, err = git.PlainOpen(dir) - utils.Logger.Info("Repository already exist, open directory repository.", zap.String("directory", dir)) - if err != nil { - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - utils.Logger.Fatal("Failed to open existing directory repository.", zap.Error(err)) - } + localCommit, err := utils.GetLatestLocalCommit(dir) + if err != nil { + utils.Logger.Fatal("Error fetching local commit.", zap.Error(err)) } - if nowFlag { - if len(args) > 0 { - utils.Logger.Info("Running command.", zap.String("command", args[0]), zap.Any("args", args[1:])) - if err := utils.RunCommand(dir, args[0], args[1:]...); err != nil { - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - utils.Logger.Error("Failed to run command.", zap.Error(err)) - } - } - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - os.Exit(0) + utils.Logger.Debug("Fetched local commit.", zap.String("localCommit", localCommit)) + + if remoteCommit == localCommit { + utils.Logger.Info( + "No changes detected.", + zap.String("url", source), + zap.String("branch", branch), + ) + time.Sleep(interval) + continue } - for { - // Get the latest commit hash from the remote repository - remoteCommit, err := utils.GetLatestRemoteCommit(r, branch) - utils.Logger.Debug("Fetched remote commit.", zap.String("remoteCommit", remoteCommit)) - if err != nil { - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - utils.Logger.Fatal("error fetching local commit.", zap.Error(err)) - } + utils.Logger.Info("Detected remote changes.", zap.String("url", source), zap.String("branch", branch)) - // Get the latest commit hash from the local repository - localCommit, err := utils.GetLatestLocalCommit(dir) - utils.Logger.Debug("Fetched local commit.", zap.String("localCommit", localCommit)) - if err != nil { - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - utils.Logger.Fatal("error fetching local commit.", zap.Error(err)) + if err := utils.PullRepo(r); err != nil { + utils.Logger.Info("Failed to pull, recloning.", zap.String("url", source)) + newR, cloneErr := utils.CloneRepo(source, branch, dir) + if cloneErr != nil { + utils.Logger.Fatal("Failed to reclone repository.", zap.Error(cloneErr)) } + r = newR + } - if remoteCommit != localCommit { - utils.Logger.Info("Detected remote changes.", zap.String("url", source), zap.String("branch", branch)) - if err := utils.PullRepo(r); err != nil { - utils.Logger.Info("Failed to pull. Recloning repository.", zap.String("url", source)) - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - _, err = utils.CloneRepo(source, branch, dir) - if err != nil { - utils.Logger.Fatal("Failed to clone repository.", zap.Error(err)) - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - } - } - if len(args) > 0 { - utils.Logger.Info("Running command.", zap.String("command", args[0]), zap.Any("args", args[1:])) - if err := utils.RunCommand(dir, args[0], args[1:]...); err != nil { - if exitFailFlag { - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - utils.Logger.Fatal("Failed to run command.", zap.Error(err)) - } - err := os.RemoveAll(dir) - if err != nil { - utils.Logger.Fatal("error removing directory.", zap.Error(err)) - } - utils.Logger.Error("Failed to run command.", zap.Error(err)) - } + if len(args) > 0 { + utils.Logger.Info("Running command.", zap.String("command", args[0]), zap.Any("args", args[1:])) + if err := utils.RunCommand(dir, args[0], args[1:]...); err != nil { + if exitFailFlag { + utils.Logger.Fatal("Failed to run command.", zap.Error(err)) } - } else { - utils.Logger.Info("No changes detected in remote repository.", zap.String("url", source), zap.String("branch", branch)) + utils.Logger.Error("Failed to run command.", zap.Error(err)) } - time.Sleep(interval) } - }, - Args: cobra.ArbitraryArgs, + + time.Sleep(interval) + } } func initConfig() { - // Your configuration initialization logic - logLevel := zapcore.InfoLevel //nolint:all + logLevel := zapcore.InfoLevel switch logLevelFlag { case "debug": logLevel = zapcore.DebugLevel case "error": logLevel = zapcore.ErrorLevel - default: - logLevel = zapcore.InfoLevel } utils.InitializeLogger(logLevel) } @@ -181,8 +176,8 @@ func Execute() { func init() { RootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "display version information") - RootCmd.Flags().BoolVarP(&nowFlag, "now", "", false, "run the command on the targeted branch now") - RootCmd.Flags().BoolVarP(&exitFailFlag, "exit-on-fail", "", false, "exit on command fail") + RootCmd.Flags().BoolVar(&nowFlag, "now", false, "run the command on the targeted branch now") + RootCmd.Flags().BoolVar(&exitFailFlag, "exit-on-fail", false, "exit on command fail") RootCmd.PersistentFlags().StringVarP(&logLevelFlag, "log-level", "l", "info", "override log level (debug, info, error)") RootCmd.PersistentFlags().StringVarP(&sourceFlag, "source", "s", "", "git repository to watch") RootCmd.PersistentFlags().StringVarP(&branchFlag, "branch", "b", "main", "branch to watch") diff --git a/coverage.out b/coverage.out new file mode 100644 index 0000000..d688eb6 --- /dev/null +++ b/coverage.out @@ -0,0 +1,85 @@ +mode: set +github.com/didactiklabs/ginx/scripts/gen_doc.go:11.13,14.16 3 0 +github.com/didactiklabs/ginx/scripts/gen_doc.go:14.16,16.3 1 0 +github.com/didactiklabs/ginx/cmd/root.go:36.55,38.3 1 0 +github.com/didactiklabs/ginx/cmd/root.go:43.43,46.17 2 0 +github.com/didactiklabs/ginx/cmd/root.go:46.17,49.3 2 0 +github.com/didactiklabs/ginx/cmd/root.go:51.2,57.16 6 0 +github.com/didactiklabs/ginx/cmd/root.go:57.16,59.3 1 0 +github.com/didactiklabs/ginx/cmd/root.go:60.2,63.16 3 0 +github.com/didactiklabs/ginx/cmd/root.go:63.16,65.3 1 0 +github.com/didactiklabs/ginx/cmd/root.go:67.2,67.13 1 0 +github.com/didactiklabs/ginx/cmd/root.go:67.13,70.3 2 0 +github.com/didactiklabs/ginx/cmd/root.go:72.2,75.51 3 0 +github.com/didactiklabs/ginx/cmd/root.go:78.68,79.33 1 0 +github.com/didactiklabs/ginx/cmd/root.go:79.33,82.3 2 0 +github.com/didactiklabs/ginx/cmd/root.go:83.2,84.27 2 0 +github.com/didactiklabs/ginx/cmd/root.go:87.41,88.20 1 0 +github.com/didactiklabs/ginx/cmd/root.go:88.20,90.3 1 0 +github.com/didactiklabs/ginx/cmd/root.go:91.2,92.68 2 0 +github.com/didactiklabs/ginx/cmd/root.go:92.68,94.3 1 0 +github.com/didactiklabs/ginx/cmd/root.go:103.3,104.6 1 0 +github.com/didactiklabs/ginx/cmd/root.go:104.6,105.10 1 0 +github.com/didactiklabs/ginx/cmd/root.go:106.21,108.10 2 0 +github.com/didactiklabs/ginx/cmd/root.go:109.11,109.11 0 0 +github.com/didactiklabs/ginx/cmd/root.go:112.3,113.17 2 0 +github.com/didactiklabs/ginx/cmd/root.go:113.17,115.4 1 0 +github.com/didactiklabs/ginx/cmd/root.go:116.3,119.17 3 0 +github.com/didactiklabs/ginx/cmd/root.go:119.17,121.4 1 0 +github.com/didactiklabs/ginx/cmd/root.go:122.3,124.34 2 0 +github.com/didactiklabs/ginx/cmd/root.go:124.34,131.12 3 0 +github.com/didactiklabs/ginx/cmd/root.go:134.3,136.43 2 0 +github.com/didactiklabs/ginx/cmd/root.go:136.43,139.23 3 0 +github.com/didactiklabs/ginx/cmd/root.go:139.23,141.5 1 0 +github.com/didactiklabs/ginx/cmd/root.go:142.4,142.12 1 0 +github.com/didactiklabs/ginx/cmd/root.go:145.3,145.20 1 0 +github.com/didactiklabs/ginx/cmd/root.go:145.20,147.70 2 0 +github.com/didactiklabs/ginx/cmd/root.go:147.70,148.21 1 0 +github.com/didactiklabs/ginx/cmd/root.go:148.21,150.6 1 0 +github.com/didactiklabs/ginx/cmd/root.go:151.5,151.65 1 0 +github.com/didactiklabs/ginx/cmd/root.go:155.3,155.23 1 0 +github.com/didactiklabs/ginx/cmd/root.go:159.19,161.22 2 0 +github.com/didactiklabs/ginx/cmd/root.go:162.15,163.32 1 0 +github.com/didactiklabs/ginx/cmd/root.go:164.15,165.32 1 0 +github.com/didactiklabs/ginx/cmd/root.go:167.2,167.34 1 0 +github.com/didactiklabs/ginx/cmd/root.go:170.16,172.16 2 0 +github.com/didactiklabs/ginx/cmd/root.go:172.16,174.3 1 0 +github.com/didactiklabs/ginx/cmd/root.go:177.13,185.2 7 0 +github.com/didactiklabs/ginx/internal/utils/git.go:13.40,14.52 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:14.52,16.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:17.2,17.13 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:20.40,22.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:22.16,24.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:25.2,26.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:26.16,28.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:29.2,30.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:30.16,32.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:33.2,34.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:34.16,36.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:37.2,38.12 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:41.69,48.16 3 0 +github.com/didactiklabs/ginx/internal/utils/git.go:48.16,50.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:51.2,52.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:52.16,54.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:55.2,56.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:56.16,58.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:59.2,60.15 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:63.64,69.2 5 0 +github.com/didactiklabs/ginx/internal/utils/git.go:71.78,73.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:73.16,75.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:76.2,79.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:79.16,81.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:82.2,83.27 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:83.27,84.36 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:84.36,86.4 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:88.2,88.16 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:91.55,93.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:93.16,95.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:96.2,97.16 2 0 +github.com/didactiklabs/ginx/internal/utils/git.go:97.16,99.3 1 0 +github.com/didactiklabs/ginx/internal/utils/git.go:100.2,100.33 1 0 +github.com/didactiklabs/ginx/internal/utils/zap.go:10.47,26.16 4 0 +github.com/didactiklabs/ginx/internal/utils/zap.go:26.16,27.13 1 0 +github.com/didactiklabs/ginx/internal/utils/zap.go:31.19,32.19 1 0 +github.com/didactiklabs/ginx/internal/utils/zap.go:32.19,34.3 1 0 +github.com/didactiklabs/ginx/main.go:5.13,7.2 1 0 diff --git a/ginx b/ginx new file mode 100755 index 0000000..c7a35bf Binary files /dev/null and b/ginx differ diff --git a/internal/utils/git.go b/internal/utils/git.go index 1ad6f54..75242c2 100644 --- a/internal/utils/git.go +++ b/internal/utils/git.go @@ -7,6 +7,7 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" + "go.uber.org/zap" ) func IsRepoCloned(dirName string) bool { @@ -17,17 +18,14 @@ func IsRepoCloned(dirName string) bool { } func PullRepo(r *git.Repository) error { - // Get the working directory for the repository w, err := r.Worktree() if err != nil { return err } - // Pull the latest changes from the origin remote and merge into the current branch err = w.Pull(&git.PullOptions{RemoteName: "origin"}) if err != nil { return err } - // Print the latest commit that was just pulled ref, err := r.Head() if err != nil { return err @@ -36,24 +34,20 @@ func PullRepo(r *git.Repository) error { if err != nil { return err } - fmt.Println(commit) + Logger.Debug("Pulled latest commit.", zap.String("commit", commit.Hash.String())) return nil } func CloneRepo(source, branch, dir string) (*git.Repository, error) { - url := source - directory := dir - // Clone the given repository to the given directory branchRefName := plumbing.NewBranchReferenceName(branch) - r, err := git.PlainClone(directory, false, &git.CloneOptions{ - URL: url, + r, err := git.PlainClone(dir, false, &git.CloneOptions{ + URL: source, RecurseSubmodules: git.DefaultSubmoduleRecursionDepth, ReferenceName: plumbing.ReferenceName(branchRefName), }) if err != nil { return r, err } - // Print the latest commit that was just pulled ref, err := r.Head() if err != nil { return r, err @@ -62,7 +56,7 @@ func CloneRepo(source, branch, dir string) (*git.Repository, error) { if err != nil { return r, err } - fmt.Println(commit) + Logger.Debug("Cloned repository.", zap.String("commit", commit.Hash.String())) return r, nil } @@ -75,26 +69,23 @@ func RunCommand(dirName, command string, args ...string) error { } func GetLatestRemoteCommit(r *git.Repository, branch string) (string, error) { - // Create the remote with repository URL rem, err := r.Remote("origin") if err != nil { return "", err } refs, err := rem.List(&git.ListOptions{ - // Returns all references, including peeled references. PeelingOption: git.IgnorePeeled, }) if err != nil { return "", err } - var refHash string + target := fmt.Sprintf("refs/heads/%s", branch) for _, ref := range refs { - if ref.Name().String() == fmt.Sprintf("refs/heads/%s", branch) { - refHash = ref.Hash().String() - break + if ref.Name().String() == target { + return ref.Hash().String(), nil } } - return refHash, nil + return "", nil } func GetLatestLocalCommit(dir string) (string, error) { @@ -102,7 +93,6 @@ func GetLatestLocalCommit(dir string) (string, error) { if err != nil { return "", err } - // Print the latest commit. ref, err := r.Head() if err != nil { return "", err diff --git a/internal/utils/zap.go b/internal/utils/zap.go index b319046..9359b81 100644 --- a/internal/utils/zap.go +++ b/internal/utils/zap.go @@ -8,18 +8,15 @@ import ( var Logger *zap.Logger func InitializeLogger(logLevel zapcore.Level) { - // Create all necessary directories for the log file - config := zap.Config{ - Level: zap.NewAtomicLevelAt(logLevel), // Set the log level + Level: zap.NewAtomicLevelAt(logLevel), Development: false, Sampling: &zap.SamplingConfig{ Initial: 100, Thereafter: 100, }, - Encoding: "json", - EncoderConfig: zap.NewProductionEncoderConfig(), - + Encoding: "json", + EncoderConfig: zap.NewProductionEncoderConfig(), OutputPaths: []string{"stdout"}, ErrorOutputPaths: []string{"stderr"}, } @@ -29,5 +26,10 @@ func InitializeLogger(logLevel zapcore.Level) { if err != nil { panic(err) } - defer Logger.Sync() //nolint:all +} + +func SyncLogger() { + if Logger != nil { + _ = Logger.Sync() + } }