v0.4.5 refactor and cleanup, minor bug fixes, default config update

This commit is contained in:
2025-09-25 17:24:14 -04:00
parent 9111d054fd
commit 15d72baafd
47 changed files with 546 additions and 522 deletions
+3 -3
View File
@@ -6,7 +6,7 @@ import (
"regexp"
)
// FilterType represents the filter type
// Represents the filter type
type FilterType string
const (
@@ -14,7 +14,7 @@ const (
FilterTypeExclude FilterType = "exclude" // Blacklist - matching logs are dropped
)
// FilterLogic represents how multiple patterns are combined
// Represents how multiple patterns are combined
type FilterLogic string
const (
@@ -22,7 +22,7 @@ const (
FilterLogicAnd FilterLogic = "and" // Match all patterns
)
// FilterConfig represents filter configuration
// Represents filter configuration
type FilterConfig struct {
Type FilterType `toml:"type"`
Logic FilterLogic `toml:"logic"`
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"strings"
)
// RateLimitPolicy defines the action to take when a rate limit is exceeded.
// Defines the action to take when a rate limit is exceeded.
type RateLimitPolicy int
const (
@@ -16,7 +16,7 @@ const (
PolicyDrop
)
// RateLimitConfig defines the configuration for pipeline-level rate limiting.
// Defines the configuration for pipeline-level rate limiting.
type RateLimitConfig struct {
// Rate is the number of log entries allowed per second. Default: 0 (disabled).
Rate float64 `toml:"rate"`
+3 -8
View File
@@ -11,11 +11,6 @@ import (
lconfig "github.com/lixenwraith/config"
)
// LoadContext holds all configuration sources
type LoadContext struct {
FlagConfig any // Parsed command-line flags from main
}
func defaults() *Config {
return &Config{
// Top-level flag defaults
@@ -69,7 +64,7 @@ func defaults() *Config {
}
}
// Load is the single entry point for loading all configuration
// Single entry point for loading all configuration
func Load(args []string) (*Config, error) {
configPath, isExplicit := resolveConfigPath(args)
// Build configuration with all sources
@@ -124,7 +119,7 @@ func Load(args []string) (*Config, error) {
return finalConfig, finalConfig.validate()
}
// resolveConfigPath returns the configuration file path
// Returns the configuration file path
func resolveConfigPath(args []string) (path string, isExplicit bool) {
// 1. Check for --config flag in command-line arguments (highest precedence)
for i, arg := range args {
@@ -167,7 +162,7 @@ func customEnvTransform(path string) string {
return env
}
// applyConsoleTargetOverrides centralizes console target configuration
// Centralizes console target configuration
func applyConsoleTargetOverrides(cfg *Config) error {
// Check environment variable for console target override
consoleTarget := os.Getenv("LOGWISP_CONSOLE_TARGET")
+5 -5
View File
@@ -3,7 +3,7 @@ package config
import "fmt"
// LogConfig represents logging configuration for LogWisp
// Represents logging configuration for LogWisp
type LogConfig struct {
// Output mode: "file", "stdout", "stderr", "both", "none"
Output string `toml:"output"`
@@ -44,10 +44,10 @@ type LogConsoleConfig struct {
Format string `toml:"format"`
}
// DefaultLogConfig returns sensible logging defaults
// Returns sensible logging defaults
func DefaultLogConfig() *LogConfig {
return &LogConfig{
Output: "stderr",
Output: "stdout",
Level: "info",
File: &LogFileConfig{
Directory: "./log",
@@ -57,7 +57,7 @@ func DefaultLogConfig() *LogConfig {
RetentionHours: 168, // 7 days
},
Console: &LogConsoleConfig{
Target: "stderr",
Target: "stdout",
Format: "txt",
},
}
@@ -66,7 +66,7 @@ func DefaultLogConfig() *LogConfig {
func validateLogConfig(cfg *LogConfig) error {
validOutputs := map[string]bool{
"file": true, "stdout": true, "stderr": true,
"both": true, "none": true,
"both": true, "all": true, "none": true,
}
if !validOutputs[cfg.Output] {
return fmt.Errorf("invalid log output mode: %s", cfg.Output)
+50 -35
View File
@@ -9,7 +9,7 @@ import (
"strings"
)
// PipelineConfig represents a data processing pipeline
// Represents a data processing pipeline
type PipelineConfig struct {
// Pipeline identifier (used in logs and metrics)
Name string `toml:"name"`
@@ -34,16 +34,16 @@ type PipelineConfig struct {
Auth *AuthConfig `toml:"auth"`
}
// SourceConfig represents an input data source
// Represents an input data source
type SourceConfig struct {
// Source type: "directory", "file", "stdin", etc.
// Source type: "directory", "stdin", "tcp", "http"
Type string `toml:"type"`
// Type-specific configuration options
Options map[string]any `toml:"options"`
}
// SinkConfig represents an output destination
// Represents an output destination
type SinkConfig struct {
// Sink type: "http", "tcp", "file", "stdout", "stderr"
Type string `toml:"type"`
@@ -59,7 +59,7 @@ func validateSource(pipelineName string, sourceIndex int, cfg *SourceConfig) err
switch cfg.Type {
case "directory":
// Validate directory source options
// Validate path
path, ok := cfg.Options["path"].(string)
if !ok || path == "" {
return fmt.Errorf("pipeline '%s' source[%d]: directory source requires 'path' option",
@@ -72,7 +72,7 @@ func validateSource(pipelineName string, sourceIndex int, cfg *SourceConfig) err
pipelineName, sourceIndex)
}
// Validate pattern if provided
// Validate pattern
if pattern, ok := cfg.Options["pattern"].(string); ok && pattern != "" {
// Try to compile as glob pattern (will be converted to regex internally)
if strings.Count(pattern, "*") == 0 && strings.Count(pattern, "?") == 0 {
@@ -84,7 +84,7 @@ func validateSource(pipelineName string, sourceIndex int, cfg *SourceConfig) err
}
}
// Validate check interval if provided
// Validate check interval
if interval, ok := cfg.Options["check_interval_ms"]; ok {
if intVal, ok := interval.(int64); ok {
if intVal < 10 {
@@ -98,17 +98,16 @@ func validateSource(pipelineName string, sourceIndex int, cfg *SourceConfig) err
}
case "stdin":
// No specific validation needed for stdin
case "http":
// Validate HTTP source options
port, ok := cfg.Options["port"].(int64)
if !ok || port < 1 || port > 65535 {
return fmt.Errorf("pipeline '%s' source[%d]: invalid or missing HTTP port",
pipelineName, sourceIndex)
// Validate buffer size
if bufSize, ok := cfg.Options["buffer_size"].(int64); ok {
if bufSize < 1 {
return fmt.Errorf("pipeline '%s' source[%d]: stdin buffer_size must be positive: %d",
pipelineName, sourceIndex, bufSize)
}
}
// Validate host if provided
case "http":
// Validate host
if host, ok := cfg.Options["host"].(string); ok && host != "" {
if net.ParseIP(host) == nil {
return fmt.Errorf("pipeline '%s' source[%d]: invalid IP address: %s",
@@ -116,22 +115,29 @@ func validateSource(pipelineName string, sourceIndex int, cfg *SourceConfig) err
}
}
// Validate path if provided
if ingestPath, ok := cfg.Options["ingest_path"].(string); ok {
if !strings.HasPrefix(ingestPath, "/") {
// Validate port
port, ok := cfg.Options["port"].(int64)
if !ok || port < 1 || port > 65535 {
return fmt.Errorf("pipeline '%s' source[%d]: invalid or missing HTTP port",
pipelineName, sourceIndex)
}
// Validate path
if path, ok := cfg.Options["ingest_path"].(string); ok {
if !strings.HasPrefix(path, "/") {
return fmt.Errorf("pipeline '%s' source[%d]: ingest path must start with /: %s",
pipelineName, sourceIndex, ingestPath)
pipelineName, sourceIndex, path)
}
}
// Validate net_limit if present within Options
// Validate net_limit
if rl, ok := cfg.Options["net_limit"].(map[string]any); ok {
if err := validateNetLimitOptions("HTTP source", pipelineName, sourceIndex, rl); err != nil {
return err
}
}
// Validate TLS if present
// Validate TLS
if tls, ok := cfg.Options["tls"].(map[string]any); ok {
if err := validateTLSOptions("HTTP source", pipelineName, sourceIndex, tls); err != nil {
return err
@@ -139,14 +145,7 @@ func validateSource(pipelineName string, sourceIndex int, cfg *SourceConfig) err
}
case "tcp":
// Validate TCP source options
port, ok := cfg.Options["port"].(int64)
if !ok || port < 1 || port > 65535 {
return fmt.Errorf("pipeline '%s' source[%d]: invalid or missing TCP port",
pipelineName, sourceIndex)
}
// Validate host if provided
// Validate host
if host, ok := cfg.Options["host"].(string); ok && host != "" {
if net.ParseIP(host) == nil {
return fmt.Errorf("pipeline '%s' source[%d]: invalid IP address: %s",
@@ -154,14 +153,21 @@ func validateSource(pipelineName string, sourceIndex int, cfg *SourceConfig) err
}
}
// Validate net_limit if present within Options
// Validate port
port, ok := cfg.Options["port"].(int64)
if !ok || port < 1 || port > 65535 {
return fmt.Errorf("pipeline '%s' source[%d]: invalid or missing TCP port",
pipelineName, sourceIndex)
}
// Validate net_limit
if rl, ok := cfg.Options["net_limit"].(map[string]any); ok {
if err := validateNetLimitOptions("TCP source", pipelineName, sourceIndex, rl); err != nil {
return err
}
}
// Validate TLS if present
// Validate TLS
if tls, ok := cfg.Options["tls"].(map[string]any); ok {
if err := validateTLSOptions("TCP source", pipelineName, sourceIndex, tls); err != nil {
return err
@@ -337,7 +343,7 @@ func validateSink(pipelineName string, sinkIndex int, cfg *SinkConfig, allPorts
}
case "tcp_client":
// FIXED: Added validation for TCP client sink
// Added validation for TCP client sink
// Validate address
address, ok := cfg.Options["address"].(string)
if !ok || address == "" {
@@ -368,20 +374,21 @@ func validateSink(pipelineName string, sinkIndex int, cfg *SinkConfig, allPorts
}
case "file":
// Validate file sink options
// Validate directory
directory, ok := cfg.Options["directory"].(string)
if !ok || directory == "" {
return fmt.Errorf("pipeline '%s' sink[%d]: file sink requires 'directory' option",
pipelineName, sinkIndex)
}
// Validate filename
name, ok := cfg.Options["name"].(string)
if !ok || name == "" {
return fmt.Errorf("pipeline '%s' sink[%d]: file sink requires 'name' option",
pipelineName, sinkIndex)
}
// Validate numeric options
// Validate size options
if maxSize, ok := cfg.Options["max_size_mb"].(int64); ok {
if maxSize < 1 {
return fmt.Errorf("pipeline '%s' sink[%d]: max_size_mb must be positive: %d",
@@ -396,6 +403,14 @@ func validateSink(pipelineName string, sinkIndex int, cfg *SinkConfig, allPorts
}
}
if minDiskFree, ok := cfg.Options["min_disk_free_mb"].(int64); ok {
if minDiskFree < 0 {
return fmt.Errorf("pipeline '%s' sink[%d]: min_disk_free_mb cannot be negative: %d",
pipelineName, sinkIndex, minDiskFree)
}
}
// Validate retention period
if retention, ok := cfg.Options["retention_hours"].(float64); ok {
if retention < 0 {
return fmt.Errorf("pipeline '%s' sink[%d]: retention_hours cannot be negative: %f",
+1 -2
View File
@@ -7,8 +7,7 @@ import (
lconfig "github.com/lixenwraith/config"
)
// SaveToFile saves the configuration to the specified file path.
// It uses the lconfig library's atomic file saving capabilities.
// Saves the configuration to the specified file path.
func (c *Config) SaveToFile(path string) error {
if path == "" {
return fmt.Errorf("cannot save config: path is empty")
+1 -1
View File
@@ -170,7 +170,7 @@ func validateNetLimitOptions(serverType, pipelineName string, sinkIndex int, rl
return nil
}
// validateIPv4Entry ensures an IP or CIDR is IPv4
// Ensures an IP or CIDR is IPv4
func validateIPv4Entry(entry string) error {
// Handle single IP
if !strings.Contains(entry, "/") {