Skip to content

Add config validation mode (dry-run) #32

@sgaunet

Description

@sgaunet

Feature Request

Add a validation-only mode that checks configuration validity without executing commands.

Use Cases

  1. CI/CD validation - Check config in pipelines
  2. Development - Validate config changes before deployment
  3. Troubleshooting - Verify config syntax and values
  4. Documentation - Example configs can be validated

Proposed CLI

# Validate default config files
logwrap --validate-config

# Validate specific config
logwrap --validate-config --config /path/to/config.yaml

# Alias
logwrap --check-config
logwrap --dry-run

Expected Output

Valid Config

$ logwrap --validate-config --config my-config.yaml
✓ Configuration is valid

Loaded from: /path/to/my-config.yaml

Settings:
  Output format: json
  Default level: INFO
  Timestamp format: %Y-%m-%d %H:%M:%S
  Colors: enabled
  Template: [{{.Timestamp}}] {{.Level}}: 

Invalid Config

$ logwrap --validate-config --config bad-config.yaml
✗ Configuration validation failed

Error: invalid output format: "xml" (valid: text, json, structured)
  in file: /path/to/bad-config.yaml
  at line: 12

Hint: Use one of: text, json, structured

Implementation

// cmd/logwrap/main.go

func validateConfigCommand(configPath string) int {
    // Load config
    cfg, err := config.Load(configPath)
    if err != nil {
        fmt.Fprintf(os.Stderr, "✗ Failed to load configuration\n\n")
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        return 1
    }
    
    // Validate config
    if err := cfg.Validate(); err != nil {
        fmt.Fprintf(os.Stderr, "✗ Configuration validation failed\n\n")
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        if configPath != "" {
            fmt.Fprintf(os.Stderr, "  in file: %s\n", configPath)
        }
        return 1
    }
    
    // Success
    fmt.Println("✓ Configuration is valid")
    fmt.Printf("\nLoaded from: %s\n", configPath)
    fmt.Println("\nSettings:")
    fmt.Printf("  Output format: %s\n", cfg.Output.Format)
    fmt.Printf("  Default level: %s\n", cfg.LogLevel.Default)
    fmt.Printf("  Timestamp format: %s\n", cfg.Prefix.Timestamp.Format)
    fmt.Printf("  Colors: %s\n", enabledStr(cfg.Colors.Enabled))
    fmt.Printf("  Template: %s\n", cfg.Prefix.Template)
    
    return 0
}

Verbose Mode

$ logwrap --validate-config --verbose
✓ Configuration is valid

Configuration details:
  Source: /home/user/.config/logwrap/config.yaml
  
  Output:
    Format: json
    Buffer: line
  
  Prefix:
    Template: [{{.Timestamp}}] {{.Level}} {{.User}}@{{.PID}}: 
    Timestamp:
      Enabled: true
      Format: %Y-%m-%d %H:%M:%S
      Timezone: UTC
    User:
      Enabled: true
    PID:
      Enabled: true
  
  Log Level:
    Default: INFO
    Detection:
      Enabled: true
      Keywords:
        ERROR: [ERROR, FATAL, PANIC]
        WARN: [WARN, WARNING]
        INFO: [INFO]
        DEBUG: [DEBUG, TRACE]
  
  Colors:
    Enabled: true
    ERROR: \x1b[31m
    WARN: \x1b[33m
    INFO: \x1b[32m
    DEBUG: \x1b[34m
    Reset: \x1b[0m

Validation checks passed:
  ✓ Output format is valid (json)
  ✓ Log level is valid (INFO)
  ✓ Timestamp format is valid (%Y-%m-%d %H:%M:%S)
  ✓ Template is valid
  ✓ Keywords are valid
  ✓ Colors are valid

JSON Output

$ logwrap --validate-config --format json
{
  "valid": true,
  "config_file": "/home/user/.config/logwrap/config.yaml",
  "settings": {
    "output": {"format": "json", "buffer": "line"},
    "log_level": {"default": "INFO"},
    "colors": {"enabled": true}
  }
}

CI/CD Integration

# .github/workflows/validate-configs.yml
name: Validate Configs

on: [pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - name: Install logwrap
        run: go install ./cmd/logwrap
      
      - name: Validate example configs
        run: |
          for config in examples/*.yaml; do
            echo "Validating $config..."
            logwrap --validate-config --config "$config" || exit 1
          done

Implementation Checklist

Core:

  • Add --validate-config flag
  • Load and validate config
  • Print success/error message
  • Return appropriate exit code

Enhanced:

  • Add --verbose flag for detailed output
  • Add --format json for machine-readable output
  • Add validation summary with checks
  • Add helpful hints for common errors

Documentation:

  • Add to README
  • Add examples
  • Add CI/CD integration guide

Testing

func TestValidateConfig(t *testing.T) {
    tests := []struct {
        name     string
        config   string
        wantErr  bool
        exitCode int
    }{
        {
            name:     "Valid config",
            config:   "testdata/valid-config.yaml",
            wantErr:  false,
            exitCode: 0,
        },
        {
            name:     "Invalid format",
            config:   "testdata/invalid-format.yaml",
            wantErr:  true,
            exitCode: 1,
        },
        {
            name:     "Invalid log level",
            config:   "testdata/invalid-level.yaml",
            wantErr:  true,
            exitCode: 1,
        },
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            exitCode := validateConfigCommand(tt.config)
            assert.Equal(t, tt.exitCode, exitCode)
        })
    }
}

Benefits

Development:

  • Catch config errors early
  • Validate before deployment
  • Test config changes

CI/CD:

  • Automated config validation
  • Prevent invalid configs in production
  • Validate example configs

Troubleshooting:

  • Easy config debugging
  • Clear error messages
  • Helpful hints

Related Issues

References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions