e1.8.0 Raw (unformatted) logging support added.

This commit is contained in:
2025-07-14 18:19:10 -04:00
parent 2e410be060
commit 146141a38e
7 changed files with 413 additions and 99 deletions

View File

@ -92,51 +92,6 @@ func parseKeyValue(arg string) (string, string, error) {
return key, value, nil
}
// validateConfigValue checks ranges and specific constraints for parsed config values.
func validateConfigValue(key string, value interface{}) error {
keyLower := strings.ToLower(key)
switch keyLower {
case "name":
if v, ok := value.(string); ok && strings.TrimSpace(v) == "" {
return fmtErrorf("log name cannot be empty")
}
case "format":
if v, ok := value.(string); ok && v != "txt" && v != "json" {
return fmtErrorf("invalid format: '%s' (use txt or json)", v)
}
case "extension":
if v, ok := value.(string); ok && strings.HasPrefix(v, ".") {
return fmtErrorf("extension should not start with dot: %s", v)
}
case "timestamp_format":
if v, ok := value.(string); ok && strings.TrimSpace(v) == "" {
return fmtErrorf("timestamp_format cannot be empty")
}
case "buffer_size":
if v, ok := value.(int64); ok && v <= 0 {
return fmtErrorf("buffer_size must be positive: %d", v)
}
case "max_size_mb", "max_total_size_mb", "min_disk_free_mb":
if v, ok := value.(int64); ok && v < 0 {
return fmtErrorf("%s cannot be negative: %d", key, v)
}
case "flush_timer", "disk_check_interval_ms", "min_check_interval_ms", "max_check_interval_ms":
if v, ok := value.(int64); ok && v <= 0 {
return fmtErrorf("%s must be positive milliseconds: %d", key, v)
}
case "trace_depth":
if v, ok := value.(int64); ok && (v < 0 || v > 10) {
return fmtErrorf("trace_depth must be between 0 and 10: %d", v)
}
case "retention_period", "retention_check_interval":
if v, ok := value.(float64); ok && v < 0 {
return fmtErrorf("%s cannot be negative: %f", key, v)
}
}
return nil
}
// Level converts level string to numeric constant.
func Level(levelStr string) (int64, error) {
switch strings.ToLower(strings.TrimSpace(levelStr)) {
@ -157,4 +112,135 @@ func Level(levelStr string) (int64, error) {
default:
return 0, fmtErrorf("invalid level string: '%s' (use debug, info, warn, error, proc, disk, sys)", levelStr)
}
}
// validateConfigValue validates a single configuration field
func validateConfigValue(key string, value any) error {
keyLower := strings.ToLower(key)
switch keyLower {
case "name":
v, ok := value.(string)
if !ok {
return fmtErrorf("name must be string, got %T", value)
}
if strings.TrimSpace(v) == "" {
return fmtErrorf("log name cannot be empty")
}
case "format":
v, ok := value.(string)
if !ok {
return fmtErrorf("format must be string, got %T", value)
}
if v != "txt" && v != "json" && v != "raw" {
return fmtErrorf("invalid format: '%s' (use txt, json, or raw)", v)
}
case "extension":
v, ok := value.(string)
if !ok {
return fmtErrorf("extension must be string, got %T", value)
}
if strings.HasPrefix(v, ".") {
return fmtErrorf("extension should not start with dot: %s", v)
}
case "timestamp_format":
v, ok := value.(string)
if !ok {
return fmtErrorf("timestamp_format must be string, got %T", value)
}
if strings.TrimSpace(v) == "" {
return fmtErrorf("timestamp_format cannot be empty")
}
case "buffer_size":
v, ok := value.(int64)
if !ok {
return fmtErrorf("buffer_size must be int64, got %T", value)
}
if v <= 0 {
return fmtErrorf("buffer_size must be positive: %d", v)
}
case "max_size_mb", "max_total_size_mb", "min_disk_free_mb":
v, ok := value.(int64)
if !ok {
return fmtErrorf("%s must be int64, got %T", key, value)
}
if v < 0 {
return fmtErrorf("%s cannot be negative: %d", key, v)
}
case "flush_interval_ms", "disk_check_interval_ms", "min_check_interval_ms", "max_check_interval_ms":
v, ok := value.(int64)
if !ok {
return fmtErrorf("%s must be int64, got %T", key, value)
}
if v <= 0 {
return fmtErrorf("%s must be positive milliseconds: %d", key, v)
}
case "trace_depth":
v, ok := value.(int64)
if !ok {
return fmtErrorf("trace_depth must be int64, got %T", value)
}
if v < 0 || v > 10 {
return fmtErrorf("trace_depth must be between 0 and 10: %d", v)
}
case "retention_period_hrs", "retention_check_mins":
v, ok := value.(float64)
if !ok {
return fmtErrorf("%s must be float64, got %T", key, value)
}
if v < 0 {
return fmtErrorf("%s cannot be negative: %f", key, v)
}
case "heartbeat_level":
v, ok := value.(int64)
if !ok {
return fmtErrorf("heartbeat_level must be int64, got %T", value)
}
if v < 0 || v > 3 {
return fmtErrorf("heartbeat_level must be between 0 and 3: %d", v)
}
case "heartbeat_interval_s":
_, ok := value.(int64)
if !ok {
return fmtErrorf("heartbeat_interval_s must be int64, got %T", value)
}
// Note: only validate positive if heartbeat is enabled (cross-field validation)
case "stdout_target":
v, ok := value.(string)
if !ok {
return fmtErrorf("stdout_target must be string, got %T", value)
}
if v != "stdout" && v != "stderr" {
return fmtErrorf("invalid stdout_target: '%s' (use stdout or stderr)", v)
}
case "level":
// Level validation if needed
_, ok := value.(int64)
if !ok {
return fmtErrorf("level must be int64, got %T", value)
}
// Fields that don't need validation beyond type
case "directory", "show_timestamp", "show_level", "enable_adaptive_interval",
"enable_periodic_sync", "enable_stdout", "disable_file", "internal_errors_to_stderr":
// Type checking handled by config system
return nil
default:
// Unknown field - let config system handle it
return nil
}
return nil
}