Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 38 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,39 @@ func LoadConfig(cmd *cobra.Command) error {
applyBoolFlag(cmd, "update-only", &Cfg.Sync.UpdateOnly)
applyStringFlag(cmd, "cache-dir", &Cfg.Sync.CacheDir)

// Compute effective log settings: config file provides defaults,
// explicit CLI flags take precedence. Do not mutate the flag-backed globals.
effectiveDebug := debug
effectiveVerbose := verbose
effectiveLogFile := logFile
effectiveLogFormat := logFormat

var unknownLogLevelMsg string
if Cfg.Log.Level != "" && !cmd.Flags().Changed("debug") && !cmd.Flags().Changed("verbose") {
switch strings.ToLower(Cfg.Log.Level) {
case "debug":
effectiveDebug = true
case "info":
effectiveVerbose = true
case "warn", "warning":
// default, no action needed
default:
unknownLogLevelMsg = fmt.Sprintf("Unknown log.level %q in config, using default (warn)", Cfg.Log.Level)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
if Cfg.Log.File != "" && !cmd.Flags().Changed("log-file") {
effectiveLogFile = Cfg.Log.File
}
if Cfg.Log.Format != "" && !cmd.Flags().Changed("log-format") {
effectiveLogFormat = Cfg.Log.Format
}

// Configure log level
var level logrus.Level
switch {
case debug:
case effectiveDebug:
level = logrus.DebugLevel
case verbose:
case effectiveVerbose:
level = logrus.InfoLevel
default:
level = logrus.WarnLevel
Expand All @@ -70,13 +97,13 @@ func LoadConfig(cmd *cobra.Command) error {

// Configure formatter
var formatter logrus.Formatter
switch strings.ToLower(logFormat) {
switch strings.ToLower(effectiveLogFormat) {
case "json":
formatter = &logrus.JSONFormatter{}
case "text", "":
formatter = &logrus.TextFormatter{FullTimestamp: true}
default:
return fmt.Errorf("invalid --log-format %q: must be 'text' or 'json'", logFormat)
return fmt.Errorf("invalid log format %q: must be 'text' or 'json'", effectiveLogFormat)
}
setAllLogFormatters(formatter)

Expand All @@ -86,15 +113,20 @@ func LoadConfig(cmd *cobra.Command) error {
_ = logFileFD.Close()
logFileFD = nil
}
if logFile != "" {
f, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if effectiveLogFile != "" {
f, err := os.OpenFile(effectiveLogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return fmt.Errorf("opening log file: %w", err)
}
logFileFD = f
setAllLogOutputs(io.MultiWriter(os.Stderr, f))
}

// Emit deferred warning after format/output are configured.
if unknownLogLevelMsg != "" {
log.Warn(unknownLogLevelMsg)
}

return nil
}

Expand Down
15 changes: 12 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,19 @@ import (

// Config holds all configuration for axm2snipe.
type Config struct {
ABM ABMConfig `yaml:"abm"`
ABM ABMConfig `yaml:"abm"`
SnipeIT SnipeITConfig `yaml:"snipe_it"`
Sync SyncConfig `yaml:"sync"`
Slack SlackConfig `yaml:"slack"`
Sync SyncConfig `yaml:"sync"`
Slack SlackConfig `yaml:"slack"`
Log LogConfig `yaml:"log"`
}

// LogConfig holds logging settings that can be set in the config file.
// CLI flags (--log-file, --log-format, -v, -d) take precedence.
type LogConfig struct {
File string `yaml:"file"` // path to log file (appended to stderr)
Format string `yaml:"format"` // "text" (default) or "json"
Level string `yaml:"level"` // "warn" (default), "info", or "debug"
}

// SlackConfig holds optional Slack webhook notification settings.
Expand Down