v0.2.1 doc update, various fixes, buggy

This commit is contained in:
2025-07-11 18:16:38 -04:00
parent b503816de3
commit 08c4df4d65
16 changed files with 632 additions and 198 deletions

View File

@ -10,6 +10,11 @@ import (
lconfig "github.com/lixenwraith/config"
)
// LoadContext holds all configuration sources
type LoadContext struct {
FlagConfig interface{} // Parsed command-line flags from main
}
func defaults() *Config {
return &Config{
Logging: DefaultLogConfig(),
@ -49,9 +54,11 @@ func defaults() *Config {
}
}
func LoadWithCLI(cliArgs []string) (*Config, error) {
// LoadWithCLI loads config with CLI flag overrides
func LoadWithCLI(cliArgs []string, flagCfg interface{}) (*Config, error) {
configPath := GetConfigPath()
// Build configuration with all sources
cfg, err := lconfig.NewBuilder().
WithDefaults(defaults()).
WithEnvPrefix("LOGWISP_").
@ -67,27 +74,86 @@ func LoadWithCLI(cliArgs []string) (*Config, error) {
Build()
if err != nil {
if strings.Contains(err.Error(), "not found") && configPath != "logwisp.toml" {
// If explicit config file specified and not found, fail
return nil, fmt.Errorf("config file not found: %s", configPath)
}
if !strings.Contains(err.Error(), "not found") {
return nil, fmt.Errorf("failed to load config: %w", err)
}
}
// Likely never happens
if cfg == nil {
return nil, fmt.Errorf("configuration builder returned nil config")
}
finalConfig := &Config{}
if err := cfg.Scan("", finalConfig); err != nil {
return nil, fmt.Errorf("failed to scan config: %w", err)
}
// Ensure we have valid config even with defaults
if finalConfig == nil {
return nil, fmt.Errorf("configuration scan produced nil config")
}
// Ensure critical fields are not nil
if finalConfig.Logging == nil {
finalConfig.Logging = DefaultLogConfig()
}
// Apply any console target transformations here
if err := applyConsoleTargetOverrides(finalConfig); err != nil {
return nil, fmt.Errorf("failed to apply console target overrides: %w", err)
}
return finalConfig, finalConfig.validate()
}
func customEnvTransform(path string) string {
env := strings.ReplaceAll(path, ".", "_")
env = strings.ToUpper(env)
env = "LOGWISP_" + env
return env
// applyConsoleTargetOverrides centralizes console target configuration
func applyConsoleTargetOverrides(cfg *Config) error {
// Check environment variable for console target override
consoleTarget := os.Getenv("LOGWISP_CONSOLE_TARGET")
if consoleTarget == "" {
return nil
}
// Validate console target value
validTargets := map[string]bool{
"stdout": true,
"stderr": true,
"split": true,
}
if !validTargets[consoleTarget] {
return fmt.Errorf("invalid LOGWISP_CONSOLE_TARGET value: %s", consoleTarget)
}
// Apply to all console sinks
for i, pipeline := range cfg.Pipelines {
for j, sink := range pipeline.Sinks {
if sink.Type == "stdout" || sink.Type == "stderr" {
if sink.Options == nil {
cfg.Pipelines[i].Sinks[j].Options = make(map[string]any)
}
// Set target for split mode handling
cfg.Pipelines[i].Sinks[j].Options["target"] = consoleTarget
}
}
}
// Also update logging console target if applicable
if cfg.Logging.Console != nil && consoleTarget == "split" {
cfg.Logging.Console.Target = "split"
}
return nil
}
// GetConfigPath returns the configuration file path
func GetConfigPath() string {
// Check if explicit config file was specified via flag or env
if configFile := os.Getenv("LOGWISP_CONFIG_FILE"); configFile != "" {
if filepath.IsAbs(configFile) {
return configFile
@ -102,9 +168,22 @@ func GetConfigPath() string {
return filepath.Join(configDir, "logwisp.toml")
}
// Default locations
if homeDir, err := os.UserHomeDir(); err == nil {
return filepath.Join(homeDir, ".config", "logwisp.toml")
configPath := filepath.Join(homeDir, ".config", "logwisp.toml")
// Check if config exists in home directory
if _, err := os.Stat(configPath); err == nil {
return configPath
}
}
// Return current directory default
return "logwisp.toml"
}
func customEnvTransform(path string) string {
env := strings.ReplaceAll(path, ".", "_")
env = strings.ToUpper(env)
env = "LOGWISP_" + env
return env
}

View File

@ -37,7 +37,7 @@ type LogFileConfig struct {
type LogConsoleConfig struct {
// Target for console output: "stdout", "stderr", "split"
// "split" means info/debug to stdout, warn/error to stderr
// "split": info/debug to stdout, warn/error to stderr
Target string `toml:"target"`
// Format: "txt" or "json"
@ -47,7 +47,7 @@ type LogConsoleConfig struct {
// DefaultLogConfig returns sensible logging defaults
func DefaultLogConfig() *LogConfig {
return &LogConfig{
Output: "stderr", // Default to stderr for containerized environments
Output: "stderr",
Level: "info",
File: &LogFileConfig{
Directory: "./logs",
@ -86,6 +86,18 @@ func validateLogConfig(cfg *LogConfig) error {
if !validTargets[cfg.Console.Target] {
return fmt.Errorf("invalid console target: %s", cfg.Console.Target)
}
// TODO: check if file output check is correct
if cfg.Console.Target == "split" && cfg.Output == "file" {
return fmt.Errorf("console target 'split' requires output mode 'stdout', 'stderr', or 'both'")
}
validFormats := map[string]bool{
"txt": true, "json": true, "": true,
}
if !validFormats[cfg.Console.Format] {
return fmt.Errorf("invalid console format: %s", cfg.Console.Format)
}
}
return nil

View File

@ -6,6 +6,14 @@ import (
)
func (c *Config) validate() error {
if c == nil {
return fmt.Errorf("config is nil")
}
if c.Logging == nil {
c.Logging = DefaultLogConfig()
}
if len(c.Pipelines) == 0 {
return fmt.Errorf("no pipelines configured")
}