// Package cli implements the logarchiver command tree (service + operator CLI) // using cobra, which also provides the `completion` subcommand the estate's // nfpm packaging installs. package cli import ( "fmt" "log/slog" "os" "strings" "git.unkin.net/unkin/logarchiver/internal/config" "github.com/spf13/cobra" ) // version is set at build time via -ldflags "-X ...cli.version=...". var version = "dev" // SetVersion lets main inject the linker-provided version string. func SetVersion(v string) { if v != "" { version = v } } var configPath string // NewRootCmd builds the root command. func NewRootCmd() *cobra.Command { root := &cobra.Command{ Use: "logarchiver", Short: "Archive NATS JetStream logs to S3 (zstd + OpenPGP) and search/retrieve them", Long: `logarchiver archives raw logs from the centralized logging JetStream stream to S3 as zstd-compressed, OpenPGP-encrypted, indexed objects, and provides a CLI to search the index and retrieve/decrypt archived logs.`, SilenceUsage: true, SilenceErrors: true, } root.PersistentFlags().StringVarP(&configPath, "config", "c", os.Getenv("LOGARCHIVER_CONFIG"), "path to config file (env LOGARCHIVER_CONFIG)") root.AddCommand( newRunCmd(), newSearchCmd(), newFetchCmd(), newInitSchemaCmd(), newVersionCmd(), ) return root } // Execute runs the root command. func Execute() int { if err := NewRootCmd().Execute(); err != nil { fmt.Fprintln(os.Stderr, "error:", err) return 1 } return 0 } func newVersionCmd() *cobra.Command { return &cobra.Command{ Use: "version", Short: "Print the version", Run: func(cmd *cobra.Command, _ []string) { _, _ = fmt.Fprintln(cmd.OutOrStdout(), version) }, } } // loadConfig loads config from the --config path (or defaults+env). func loadConfig() (config.Config, error) { return config.Load(configPath) } // newLogger builds a slog logger from config. func newLogger(cfg config.LogConfig) *slog.Logger { level := slog.LevelInfo switch strings.ToLower(cfg.Level) { case "debug": level = slog.LevelDebug case "warn": level = slog.LevelWarn case "error": level = slog.LevelError } opts := &slog.HandlerOptions{Level: level} var h slog.Handler if strings.ToLower(cfg.Format) == "text" { h = slog.NewTextHandler(os.Stderr, opts) } else { h = slog.NewJSONHandler(os.Stderr, opts) } return slog.New(h) }