Skip to content

Commit e1cb144

Browse files
authored
feat(cmd): add debug mode flag (#10)
1 parent 843050c commit e1cb144

File tree

8 files changed

+171
-9
lines changed

8 files changed

+171
-9
lines changed

README.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,62 @@ iwr https://kuba.mwco.app/install.ps1 -useb | iex
129129
kuba run -- <your-command>
130130
```
131131

132-
This will fetch all secrets definded in
132+
This will fetch all secrets defined in
133133
`kuba.yaml` and pass them as
134134
environment variables to any arbitrary command.
135135

136+
### Debug Mode
137+
138+
For troubleshooting configuration issues and seeing detailed execution steps, you can enable debug mode:
139+
140+
```sh
141+
kuba --debug run -- <your-command>
142+
# or use the short form
143+
kuba -d run -- <your-command>
144+
```
145+
146+
Debug mode provides verbose logging that shows:
147+
- Configuration file discovery and loading
148+
- Environment selection and validation
149+
- Secret provider initialization
150+
- Secret retrieval attempts and results
151+
- Environment variable mapping
152+
- Command execution details
153+
154+
This is particularly useful for:
155+
- Diagnosing cloud provider authentication issues
156+
- Troubleshooting configuration file syntax errors
157+
- Understanding why certain secrets aren't being loaded
158+
- Verifying environment variable interpolation
159+
- Debugging provider-specific errors
160+
161+
### Available Commands and Flags
162+
163+
Kuba provides several commands to help you manage your configuration:
164+
165+
```sh
166+
# Initialize a new configuration file
167+
kuba init
168+
169+
# Run a command with secrets
170+
kuba run -- <command>
171+
172+
# Show version information
173+
kuba version
174+
175+
# Get help
176+
kuba --help
177+
```
178+
179+
**Global Flags:**
180+
- `--debug, -d`: Enable debug mode for verbose logging
181+
- `--version`: Show version information
182+
- `--help, -h`: Show help information
183+
184+
**Run Command Flags:**
185+
- `--env, -e`: Specify environment (default: "default")
186+
- `--config, -c`: Path to configuration file
187+
136188
Let's say you want to pass
137189
some secrets from GCP to your node application.
138190

cmd/kuba/init.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package kuba
22

33
import (
44
"github.com/mistweaverco/kuba/internal/lib/fileutils"
5+
"github.com/mistweaverco/kuba/internal/lib/log"
56
"github.com/spf13/cobra"
67
)
78

@@ -10,6 +11,14 @@ var initCmd = &cobra.Command{
1011
Short: "Create a default configuration file",
1112
Long: "This command initializes a default configuration file for kuba, if it does not already exist.",
1213
Run: func(cmd *cobra.Command, files []string) {
13-
fileutils.GenerateDefaultKubaConfig()
14+
logger := log.NewLogger()
15+
logger.Debug("Initializing default kuba configuration")
16+
17+
created := fileutils.GenerateDefaultKubaConfig()
18+
if created {
19+
logger.Debug("Default configuration file created successfully")
20+
} else {
21+
logger.Debug("Configuration file already exists, no action taken")
22+
}
1423
},
1524
}

cmd/kuba/kuba.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"os"
66

77
"github.com/mistweaverco/kuba/internal/config"
8+
"github.com/mistweaverco/kuba/internal/lib/log"
89
"github.com/mistweaverco/kuba/internal/lib/version"
910
"github.com/spf13/cobra"
1011
)
@@ -17,6 +18,10 @@ var rootCmd = &cobra.Command{
1718
Use: "kuba",
1819
Short: "Kuba CLI",
1920
Long: "Kuba is a CLI tool for accessing secrets and environment variables in a secure and efficient way.",
21+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
22+
// Initialize logging with debug mode
23+
log.SetDebugMode(cfg.Flags.Debug)
24+
},
2025
Run: func(cmd *cobra.Command, files []string) {
2126
if cfg.Flags.Version {
2227
fmt.Println(version.VERSION)
@@ -39,6 +44,7 @@ func init() {
3944
rootCmd.AddCommand(initCmd)
4045
// runCmd is added in run.go init() function
4146
rootCmd.PersistentFlags().BoolVar(&cfg.Flags.Version, "version", false, "Kuba version")
47+
rootCmd.PersistentFlags().BoolVarP(&cfg.Flags.Debug, "debug", "d", false, "Enable debug mode for verbose logging")
4248
}
4349

4450
// osExit is a variable to allow overriding in tests

cmd/kuba/run.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os/exec"
88

99
"github.com/mistweaverco/kuba/internal/config"
10+
"github.com/mistweaverco/kuba/internal/lib/log"
1011
"github.com/mistweaverco/kuba/internal/lib/secrets"
1112
"github.com/spf13/cobra"
1213
)
@@ -44,40 +45,54 @@ func init() {
4445
}
4546

4647
func runCommand(args []string) error {
48+
logger := log.NewLogger()
49+
4750
// Find configuration file if not specified
4851
if configFile == "" {
4952
var err error
53+
logger.Debug("No config file specified, searching for kuba.yaml")
5054
configFile, err = config.FindConfigFile()
5155
if err != nil {
5256
return fmt.Errorf("failed to find configuration file: %w", err)
5357
}
58+
logger.Debug("Found configuration file", "path", configFile)
59+
} else {
60+
logger.Debug("Using specified configuration file", "path", configFile)
5461
}
5562

5663
// Load configuration
64+
logger.Debug("Loading configuration from file")
5765
kubaConfig, err := config.LoadKubaConfig(configFile)
5866
if err != nil {
5967
return fmt.Errorf("failed to load configuration: %w", err)
6068
}
69+
logger.Debug("Configuration loaded successfully")
6170

6271
// Get environment configuration
72+
logger.Debug("Getting environment configuration", "environment", environment)
6373
env, err := kubaConfig.GetEnvironment(environment)
6474
if err != nil {
6575
return fmt.Errorf("failed to get environment '%s': %w", environment, err)
6676
}
77+
logger.Debug("Environment configuration retrieved", "environment", environment, "provider", env.Provider, "mappings_count", len(env.Mappings))
6778

6879
// Create secrets manager factory
80+
logger.Debug("Creating secrets manager factory")
6981
factory := secrets.NewSecretManagerFactory()
7082

7183
// Get secrets for the environment
7284
ctx := context.Background()
85+
logger.Debug("Fetching secrets from cloud providers")
7386
secrets, err := factory.GetSecretsForEnvironment(ctx, env)
7487
if err != nil {
7588
return fmt.Errorf("failed to get secrets: %w", err)
7689
}
90+
logger.Debug("Secrets retrieved successfully", "count", len(secrets))
7791

7892
// Prepare command
7993
command := args[0]
8094
commandArgs := args[1:]
95+
logger.Debug("Preparing command execution", "command", command, "args", commandArgs)
8196

8297
// Create command
8398
cmd := exec.Command(command, commandArgs...)
@@ -90,14 +105,18 @@ func runCommand(args []string) error {
90105
for key, value := range secrets {
91106
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
92107
}
108+
logger.Debug("Environment variables set", "secrets_count", len(secrets), "total_env_vars", len(cmd.Env))
93109

94110
// Execute command
111+
logger.Debug("Executing command")
95112
if err := cmd.Run(); err != nil {
96113
if exitErr, ok := err.(*exec.ExitError); ok {
114+
logger.Debug("Command exited with non-zero status", "exit_code", exitErr.ExitCode())
97115
os.Exit(exitErr.ExitCode())
98116
}
99117
return fmt.Errorf("command failed: %w", err)
100118
}
101119

120+
logger.Debug("Command executed successfully")
102121
return nil
103122
}

internal/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package config
22

33
type ConfigFlags struct {
44
Version bool
5+
Debug bool
56
}
67

78
type Config struct {

internal/config/kuba_config.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"regexp"
88
"strings"
99

10+
"github.com/mistweaverco/kuba/internal/lib/log"
1011
"gopkg.in/yaml.v3"
1112
)
1213

@@ -151,54 +152,90 @@ func processValueInterpolations(config *KubaConfig) error {
151152

152153
// LoadKubaConfig loads the kuba.yaml configuration file
153154
func LoadKubaConfig(configPath string) (*KubaConfig, error) {
155+
logger := log.NewLogger()
156+
154157
if configPath == "" {
155158
configPath = "kuba.yaml"
156159
}
157160

161+
logger.Debug("Loading configuration file", "path", configPath)
162+
158163
// Check if file exists
159164
if _, err := os.Stat(configPath); os.IsNotExist(err) {
165+
logger.Debug("Configuration file not found", "path", configPath)
160166
return nil, fmt.Errorf("configuration file not found: %s", configPath)
161167
}
162168

163169
// Read file
170+
logger.Debug("Reading configuration file")
164171
data, err := os.ReadFile(configPath)
165172
if err != nil {
173+
logger.Debug("Failed to read configuration file", "path", configPath, "error", err)
166174
return nil, fmt.Errorf("failed to read configuration file: %w", err)
167175
}
168176

177+
logger.Debug("Configuration file read successfully", "size_bytes", len(data))
178+
169179
// Parse YAML
180+
logger.Debug("Parsing YAML configuration")
170181
var config KubaConfig
171182
if err := yaml.Unmarshal(data, &config); err != nil {
183+
logger.Debug("Failed to parse YAML configuration", "error", err)
172184
return nil, fmt.Errorf("failed to parse configuration file: %w", err)
173185
}
174186

187+
logger.Debug("YAML parsed successfully", "environments_count", len(config.Environments))
188+
175189
// Process environment variable interpolations
190+
logger.Debug("Processing environment variable interpolations")
176191
if err := processValueInterpolations(&config); err != nil {
192+
logger.Debug("Failed to process environment variable interpolations", "error", err)
177193
return nil, fmt.Errorf("failed to process environment variable interpolations: %w", err)
178194
}
179195

196+
logger.Debug("Environment variable interpolations processed successfully")
197+
180198
// Validate configuration
199+
logger.Debug("Validating configuration")
181200
if err := validateConfig(&config); err != nil {
201+
logger.Debug("Configuration validation failed", "error", err)
182202
return nil, fmt.Errorf("invalid configuration: %w", err)
183203
}
184204

205+
logger.Debug("Configuration validation passed")
185206
return &config, nil
186207
}
187208

188209
// GetEnvironment returns the configuration for a specific environment
189210
func (c *KubaConfig) GetEnvironment(envName string) (*Environment, error) {
211+
logger := log.NewLogger()
212+
190213
if envName == "" {
191214
envName = "default"
215+
logger.Debug("No environment specified, using default")
192216
}
193217

218+
logger.Debug("Getting environment configuration", "requested_env", envName, "available_environments", len(c.Environments))
219+
194220
env, exists := c.Environments[envName]
195221
if !exists {
222+
logger.Debug("Environment not found in configuration", "requested_env", envName, "available_environments", getEnvironmentNames(c.Environments))
196223
return nil, fmt.Errorf("environment '%s' not found in configuration", envName)
197224
}
198225

226+
logger.Debug("Environment configuration retrieved", "environment", envName, "provider", env.Provider, "project", env.Project, "mappings_count", len(env.Mappings))
199227
return &env, nil
200228
}
201229

230+
// getEnvironmentNames returns a slice of available environment names
231+
func getEnvironmentNames(environments map[string]Environment) []string {
232+
names := make([]string, 0, len(environments))
233+
for name := range environments {
234+
names = append(names, name)
235+
}
236+
return names
237+
}
238+
202239
// validateConfig validates the configuration structure
203240
func validateConfig(config *KubaConfig) error {
204241
if len(config.Environments) == 0 {

internal/lib/log/log.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,29 @@ import (
77
"github.com/mistweaverco/kuba/internal/lib/version"
88
)
99

10-
var logLevel slog.Level = slog.LevelDebug
10+
var logLevel slog.Level = slog.LevelInfo
1111

1212
func SetLogLevel(level slog.Level) {
13+
logLevel = level
1314
slog.SetLogLoggerLevel(level)
1415
}
1516

17+
func SetDebugMode(debug bool) {
18+
if debug {
19+
SetLogLevel(slog.LevelDebug)
20+
} else {
21+
SetLogLevel(slog.LevelInfo)
22+
}
23+
}
24+
25+
func IsDebugMode() bool {
26+
return logLevel <= slog.LevelDebug
27+
}
28+
1629
func NewLogger() *slog.Logger {
1730
// When running in a production environment,
18-
// set the log level to Error
19-
if version.VERSION != "" {
31+
// set the log level to Error unless debug mode is enabled
32+
if version.VERSION != "" && logLevel > slog.LevelDebug {
2033
logLevel = slog.LevelError
2134
}
2235
return slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel}))

0 commit comments

Comments
 (0)