package main import ( "fmt" "log" "github.com/spf13/viper" ) type WebConfig struct { Enabled bool `mapstructure:"enabled"` Port int `mapstructure:"port"` Host string `mapstructure:"host"` } type LogFormat struct { Name string `mapstructure:"name"` Pattern string `mapstructure:"pattern"` Fields map[string]string `mapstructure:"fields"` } type ToolConfig struct { Name string `mapstructure:"name"` LogFile string `mapstructure:"log_file"` Format LogFormat `mapstructure:"format"` Enabled bool `mapstructure:"enabled"` BufferSize int `mapstructure:"buffer_size"` } type ServiceConfig struct { Name string `mapstructure:"name"` Service string `mapstructure:"service"` Enabled bool `mapstructure:"enabled"` SinceTime string `mapstructure:"since_time"` Priority string `mapstructure:"priority"` } type ElasticsearchConfig struct { URL string `mapstructure:"url"` Index string `mapstructure:"index"` Username string `mapstructure:"username"` Password string `mapstructure:"password"` Timeout int `mapstructure:"timeout"` } type SystemMetrics struct { Enabled bool `mapstructure:"enabled"` CollectCPU bool `mapstructure:"collect_cpu"` CollectMemory bool `mapstructure:"collect_memory"` CollectDisk bool `mapstructure:"collect_disk"` CollectNetwork bool `mapstructure:"collect_network"` DiskPaths []string `mapstructure:"disk_paths"` NetworkInterfaces []string `mapstructure:"network_interfaces"` } type Config struct { Elasticsearch ElasticsearchConfig `mapstructure:"elasticsearch"` Tools []ToolConfig `mapstructure:"tools"` Services []ServiceConfig `mapstructure:"services"` PollIntervalSeconds int `mapstructure:"poll_interval_seconds"` SystemMetrics SystemMetrics `mapstructure:"system_metrics"` WebService WebConfig `mapstructure:"web_service"` Logging struct { Level string `mapstructure:"level"` FilePath string `mapstructure:"file_path"` } `mapstructure:"logging"` } func LoadConfig() (*Config, error) { viper.SetConfigName("config") viper.AddConfigPath(".") viper.AddConfigPath("/opt/tixel/tixel-watch/") viper.SetConfigType("yaml") setConfigDefaults() if err := viper.ReadInConfig(); err != nil { return nil, fmt.Errorf("error reading config: %w", err) } var cfg Config if err := viper.Unmarshal(&cfg); err != nil { return nil, fmt.Errorf("error parsing config: %w", err) } if err := validateConfig(&cfg); err != nil { return nil, fmt.Errorf("config validation failed: %w", err) } return &cfg, nil } func setConfigDefaults() { viper.SetDefault("poll_interval_seconds", 30) viper.SetDefault("elasticsearch.timeout", 30) viper.SetDefault("system_metrics.enabled", true) viper.SetDefault("system_metrics.collect_cpu", true) viper.SetDefault("system_metrics.collect_memory", true) viper.SetDefault("system_metrics.collect_disk", true) viper.SetDefault("system_metrics.collect_network", false) viper.SetDefault("system_metrics.disk_paths", []string{"/"}) viper.SetDefault("web_service.enabled", false) viper.SetDefault("web_service.port", 8080) viper.SetDefault("web_service.host", "localhost") viper.SetDefault("logging.level", "info") } func validateConfig(cfg *Config) error { if cfg.Elasticsearch.URL == "" { return fmt.Errorf("elasticsearch.url is required") } if cfg.Elasticsearch.Index == "" { return fmt.Errorf("elasticsearch.index is required") } if cfg.PollIntervalSeconds <= 0 { log.Printf("Warning: poll_interval_seconds is %d, setting to 30", cfg.PollIntervalSeconds) cfg.PollIntervalSeconds = 30 } for i := range cfg.Tools { if cfg.Tools[i].BufferSize <= 0 { cfg.Tools[i].BufferSize = 100 } } return nil }