e1.10.0 Configuration refactored.
This commit is contained in:
129
state.go
129
state.go
@ -2,15 +2,15 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/lixenwraith/config"
|
||||
)
|
||||
|
||||
// State encapsulates the runtime state of the logger
|
||||
@ -46,11 +46,12 @@ type sink struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
// Init initializes or reconfigures the logger using the provided config.Config instance
|
||||
func (l *Logger) Init(cfg *config.Config, basePath string) error {
|
||||
if cfg == nil {
|
||||
// Init initializes the logger using a map of configuration values
|
||||
func (l *Logger) Init(values map[string]any) error {
|
||||
cfg, err := NewConfigFromDefaults(values)
|
||||
if err != nil {
|
||||
l.state.LoggerDisabled.Store(true)
|
||||
return fmtErrorf("config instance cannot be nil")
|
||||
return err
|
||||
}
|
||||
|
||||
l.initMu.Lock()
|
||||
@ -60,71 +61,78 @@ func (l *Logger) Init(cfg *config.Config, basePath string) error {
|
||||
return fmtErrorf("logger previously failed to initialize and is disabled")
|
||||
}
|
||||
|
||||
if err := l.updateConfigFromExternal(cfg, basePath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return l.applyConfig()
|
||||
return l.apply(cfg)
|
||||
}
|
||||
|
||||
// InitWithDefaults initializes the logger with built-in defaults and optional overrides
|
||||
func (l *Logger) InitWithDefaults(overrides ...string) error {
|
||||
l.initMu.Lock()
|
||||
defer l.initMu.Unlock()
|
||||
|
||||
if l.state.LoggerDisabled.Load() {
|
||||
return fmtErrorf("logger previously failed to initialize and is disabled")
|
||||
}
|
||||
// Parse overrides into a map
|
||||
overrideMap := make(map[string]any)
|
||||
|
||||
defaults := DefaultConfig()
|
||||
for _, override := range overrides {
|
||||
key, valueStr, err := parseKeyValue(override)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keyLower := strings.ToLower(key)
|
||||
path := "log." + keyLower
|
||||
|
||||
if _, exists := l.config.Get(path); !exists {
|
||||
return fmtErrorf("unknown config key in override: %s", key)
|
||||
}
|
||||
|
||||
currentVal, found := l.config.Get(path)
|
||||
if !found {
|
||||
return fmtErrorf("failed to get current value for '%s'", key)
|
||||
}
|
||||
|
||||
var parsedValue any
|
||||
var parseErr error
|
||||
|
||||
switch currentVal.(type) {
|
||||
case int64:
|
||||
parsedValue, parseErr = strconv.ParseInt(valueStr, 10, 64)
|
||||
case string:
|
||||
parsedValue = valueStr
|
||||
case bool:
|
||||
parsedValue, parseErr = strconv.ParseBool(valueStr)
|
||||
case float64:
|
||||
parsedValue, parseErr = strconv.ParseFloat(valueStr, 64)
|
||||
default:
|
||||
return fmtErrorf("unsupported type for key '%s'", key)
|
||||
}
|
||||
|
||||
if parseErr != nil {
|
||||
return fmtErrorf("invalid value format for '%s': %w", key, parseErr)
|
||||
}
|
||||
|
||||
if err := validateConfigValue(keyLower, parsedValue); err != nil {
|
||||
return fmtErrorf("invalid value for '%s': %w", key, err)
|
||||
}
|
||||
|
||||
err = l.config.Set(path, parsedValue)
|
||||
fieldType, err := getFieldType(defaults, key)
|
||||
if err != nil {
|
||||
return fmtErrorf("failed to update config value for '%s': %w", key, err)
|
||||
return fmtErrorf("unknown config key: %s", key)
|
||||
}
|
||||
|
||||
// Parse the value based on the field type
|
||||
var parsedValue any
|
||||
switch fieldType {
|
||||
case "int64":
|
||||
parsedValue, err = strconv.ParseInt(valueStr, 10, 64)
|
||||
case "string":
|
||||
parsedValue = valueStr
|
||||
case "bool":
|
||||
parsedValue, err = strconv.ParseBool(valueStr)
|
||||
case "float64":
|
||||
parsedValue, err = strconv.ParseFloat(valueStr, 64)
|
||||
default:
|
||||
return fmtErrorf("unsupported type for key '%s': %s", key, fieldType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmtErrorf("invalid value format for '%s': %w", key, err)
|
||||
}
|
||||
|
||||
overrideMap[strings.ToLower(key)] = parsedValue
|
||||
}
|
||||
|
||||
return l.Init(overrideMap)
|
||||
}
|
||||
|
||||
// getFieldType uses reflection to determine the type of a config field
|
||||
func getFieldType(cfg *Config, fieldName string) (string, error) {
|
||||
v := reflect.ValueOf(cfg).Elem()
|
||||
t := v.Type()
|
||||
|
||||
fieldName = strings.ToLower(fieldName)
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
tomlTag := field.Tag.Get("toml")
|
||||
if strings.ToLower(tomlTag) == fieldName {
|
||||
switch field.Type.Kind() {
|
||||
case reflect.String:
|
||||
return "string", nil
|
||||
case reflect.Int64:
|
||||
return "int64", nil
|
||||
case reflect.Float64:
|
||||
return "float64", nil
|
||||
case reflect.Bool:
|
||||
return "bool", nil
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported field type: %v", field.Type.Kind())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return l.applyConfig()
|
||||
return "", fmt.Errorf("field not found")
|
||||
}
|
||||
|
||||
// Shutdown gracefully closes the logger, attempting to flush pending records
|
||||
@ -154,17 +162,18 @@ func (l *Logger) Shutdown(timeout ...time.Duration) error {
|
||||
}
|
||||
l.initMu.Unlock()
|
||||
|
||||
c := l.getConfig()
|
||||
var effectiveTimeout time.Duration
|
||||
if len(timeout) > 0 {
|
||||
effectiveTimeout = timeout[0]
|
||||
} else {
|
||||
flushIntervalMs := c.FlushIntervalMs
|
||||
// Default to 2x flush interval
|
||||
flushMs, _ := l.config.Int64("log.flush_interval_ms")
|
||||
effectiveTimeout = 2 * time.Duration(flushMs) * time.Millisecond
|
||||
effectiveTimeout = 2 * time.Duration(flushIntervalMs) * time.Millisecond
|
||||
}
|
||||
|
||||
deadline := time.Now().Add(effectiveTimeout)
|
||||
pollInterval := 10 * time.Millisecond // Reasonable check period
|
||||
pollInterval := minWaitTime // Reasonable check period
|
||||
processorCleanlyExited := false
|
||||
for time.Now().Before(deadline) {
|
||||
if l.state.ProcessorExited.Load() {
|
||||
@ -216,7 +225,7 @@ func (l *Logger) Flush(timeout time.Duration) error {
|
||||
select {
|
||||
case l.state.flushRequestChan <- confirmChan:
|
||||
// Request sent
|
||||
case <-time.After(10 * time.Millisecond): // Short timeout to prevent blocking if processor is stuck
|
||||
case <-time.After(minWaitTime): // Short timeout to prevent blocking if processor is stuck
|
||||
return fmtErrorf("failed to send flush request to processor (possible deadlock or high load)")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user