e3.0.0 Tests added, optimization, bug fixes, builder changed.
This commit is contained in:
213
config.go
213
config.go
@ -1,7 +1,9 @@
|
||||
// FILE: config.go
|
||||
// FILE: lixenwraith/log/config.go
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@ -22,9 +24,9 @@ type Config struct {
|
||||
|
||||
// Buffer and size limits
|
||||
BufferSize int64 `toml:"buffer_size"` // Channel buffer size
|
||||
MaxSizeMB int64 `toml:"max_size_mb"` // Max size per log file
|
||||
MaxTotalSizeMB int64 `toml:"max_total_size_mb"` // Max total size of all logs in dir
|
||||
MinDiskFreeMB int64 `toml:"min_disk_free_mb"` // Minimum free disk space required
|
||||
MaxSizeKB int64 `toml:"max_size_kb"` // Max size per log file
|
||||
MaxTotalSizeKB int64 `toml:"max_total_size_kb"` // Max total size of all logs in dir
|
||||
MinDiskFreeKB int64 `toml:"min_disk_free_kb"` // Minimum free disk space required
|
||||
|
||||
// Timers
|
||||
FlushIntervalMs int64 `toml:"flush_interval_ms"` // Interval for flushing file buffer
|
||||
@ -57,7 +59,7 @@ var defaultConfig = Config{
|
||||
// Basic settings
|
||||
Level: LevelInfo,
|
||||
Name: "log",
|
||||
Directory: "./logs",
|
||||
Directory: "./log",
|
||||
Format: "txt",
|
||||
Extension: "log",
|
||||
|
||||
@ -68,9 +70,9 @@ var defaultConfig = Config{
|
||||
|
||||
// Buffer and size limits
|
||||
BufferSize: 1024,
|
||||
MaxSizeMB: 10,
|
||||
MaxTotalSizeMB: 50,
|
||||
MinDiskFreeMB: 100,
|
||||
MaxSizeKB: 1000,
|
||||
MaxTotalSizeKB: 5000,
|
||||
MinDiskFreeKB: 10000,
|
||||
|
||||
// Timers
|
||||
FlushIntervalMs: 100,
|
||||
@ -138,7 +140,7 @@ func (c *Config) Validate() error {
|
||||
return fmtErrorf("buffer_size must be positive: %d", c.BufferSize)
|
||||
}
|
||||
|
||||
if c.MaxSizeMB < 0 || c.MaxTotalSizeMB < 0 || c.MinDiskFreeMB < 0 {
|
||||
if c.MaxSizeKB < 0 || c.MaxTotalSizeKB < 0 || c.MinDiskFreeKB < 0 {
|
||||
return fmtErrorf("size limits cannot be negative")
|
||||
}
|
||||
|
||||
@ -171,4 +173,197 @@ func (c *Config) Validate() error {
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyConfigField applies a single key-value override to a Config.
|
||||
// This is the core field mapping logic for string overrides.
|
||||
func applyConfigField(cfg *Config, key, value string) error {
|
||||
switch key {
|
||||
// Basic settings
|
||||
case "level":
|
||||
// Special handling: accept both numeric and named values
|
||||
if numVal, err := strconv.ParseInt(value, 10, 64); err == nil {
|
||||
cfg.Level = numVal
|
||||
} else {
|
||||
// Try parsing as named level
|
||||
levelVal, err := Level(value)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid level value '%s': %w", value, err)
|
||||
}
|
||||
cfg.Level = levelVal
|
||||
}
|
||||
case "name":
|
||||
cfg.Name = value
|
||||
case "directory":
|
||||
cfg.Directory = value
|
||||
case "format":
|
||||
cfg.Format = value
|
||||
case "extension":
|
||||
cfg.Extension = value
|
||||
|
||||
// Formatting
|
||||
case "show_timestamp":
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid boolean value for show_timestamp '%s': %w", value, err)
|
||||
}
|
||||
cfg.ShowTimestamp = boolVal
|
||||
case "show_level":
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid boolean value for show_level '%s': %w", value, err)
|
||||
}
|
||||
cfg.ShowLevel = boolVal
|
||||
case "timestamp_format":
|
||||
cfg.TimestampFormat = value
|
||||
|
||||
// Buffer and size limits
|
||||
case "buffer_size":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for buffer_size '%s': %w", value, err)
|
||||
}
|
||||
cfg.BufferSize = intVal
|
||||
case "max_size_mb":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for max_size_mb '%s': %w", value, err)
|
||||
}
|
||||
cfg.MaxSizeKB = intVal
|
||||
case "max_total_size_mb":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for max_total_size_mb '%s': %w", value, err)
|
||||
}
|
||||
cfg.MaxTotalSizeKB = intVal
|
||||
case "min_disk_free_mb":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for min_disk_free_mb '%s': %w", value, err)
|
||||
}
|
||||
cfg.MinDiskFreeKB = intVal
|
||||
|
||||
// Timers
|
||||
case "flush_interval_ms":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for flush_interval_ms '%s': %w", value, err)
|
||||
}
|
||||
cfg.FlushIntervalMs = intVal
|
||||
case "trace_depth":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for trace_depth '%s': %w", value, err)
|
||||
}
|
||||
cfg.TraceDepth = intVal
|
||||
case "retention_period_hrs":
|
||||
floatVal, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid float value for retention_period_hrs '%s': %w", value, err)
|
||||
}
|
||||
cfg.RetentionPeriodHrs = floatVal
|
||||
case "retention_check_mins":
|
||||
floatVal, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid float value for retention_check_mins '%s': %w", value, err)
|
||||
}
|
||||
cfg.RetentionCheckMins = floatVal
|
||||
|
||||
// Disk check settings
|
||||
case "disk_check_interval_ms":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for disk_check_interval_ms '%s': %w", value, err)
|
||||
}
|
||||
cfg.DiskCheckIntervalMs = intVal
|
||||
case "enable_adaptive_interval":
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid boolean value for enable_adaptive_interval '%s': %w", value, err)
|
||||
}
|
||||
cfg.EnableAdaptiveInterval = boolVal
|
||||
case "enable_periodic_sync":
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid boolean value for enable_periodic_sync '%s': %w", value, err)
|
||||
}
|
||||
cfg.EnablePeriodicSync = boolVal
|
||||
case "min_check_interval_ms":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for min_check_interval_ms '%s': %w", value, err)
|
||||
}
|
||||
cfg.MinCheckIntervalMs = intVal
|
||||
case "max_check_interval_ms":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for max_check_interval_ms '%s': %w", value, err)
|
||||
}
|
||||
cfg.MaxCheckIntervalMs = intVal
|
||||
|
||||
// Heartbeat configuration
|
||||
case "heartbeat_level":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for heartbeat_level '%s': %w", value, err)
|
||||
}
|
||||
cfg.HeartbeatLevel = intVal
|
||||
case "heartbeat_interval_s":
|
||||
intVal, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid integer value for heartbeat_interval_s '%s': %w", value, err)
|
||||
}
|
||||
cfg.HeartbeatIntervalS = intVal
|
||||
|
||||
// Stdout/console output settings
|
||||
case "enable_stdout":
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid boolean value for enable_stdout '%s': %w", value, err)
|
||||
}
|
||||
cfg.EnableStdout = boolVal
|
||||
case "stdout_target":
|
||||
cfg.StdoutTarget = value
|
||||
case "disable_file":
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid boolean value for disable_file '%s': %w", value, err)
|
||||
}
|
||||
cfg.DisableFile = boolVal
|
||||
|
||||
// Internal error handling
|
||||
case "internal_errors_to_stderr":
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid boolean value for internal_errors_to_stderr '%s': %w", value, err)
|
||||
}
|
||||
cfg.InternalErrorsToStderr = boolVal
|
||||
|
||||
default:
|
||||
return fmtErrorf("unknown configuration key '%s'", key)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// combineConfigErrors combines multiple configuration errors into a single error.
|
||||
func combineConfigErrors(errors []error) error {
|
||||
if len(errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(errors) == 1 {
|
||||
return errors[0]
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
sb.WriteString("log: multiple configuration errors:")
|
||||
for i, err := range errors {
|
||||
errMsg := err.Error()
|
||||
// Remove "log: " prefix from individual errors to avoid duplication
|
||||
if strings.HasPrefix(errMsg, "log: ") {
|
||||
errMsg = errMsg[5:]
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("\n %d. %s", i+1, errMsg))
|
||||
}
|
||||
return fmt.Errorf("%s", sb.String())
|
||||
}
|
||||
Reference in New Issue
Block a user