e1.2.1 Readme update and comment cleanup.

This commit is contained in:
2025-04-24 15:31:49 -04:00
parent bfed212f40
commit 764caeb894
8 changed files with 118 additions and 134 deletions

View File

@ -54,12 +54,10 @@ func (l *Logger) Init(cfg *config.Config, basePath string) error {
return fmtErrorf("logger previously failed to initialize and is disabled")
}
// Update configuration from external config
if err := l.updateConfigFromExternal(cfg, basePath); err != nil {
return err
}
// Apply configuration and reconfigure logger components
return l.applyAndReconfigureLocked()
}
@ -72,7 +70,6 @@ func (l *Logger) InitWithDefaults(overrides ...string) error {
return fmtErrorf("logger previously failed to initialize and is disabled")
}
// Apply provided overrides
for _, override := range overrides {
key, valueStr, err := parseKeyValue(override)
if err != nil {
@ -82,18 +79,15 @@ func (l *Logger) InitWithDefaults(overrides ...string) error {
keyLower := strings.ToLower(key)
path := "log." + keyLower
// Check if this is a valid config key
if _, exists := l.config.Get(path); !exists {
return fmtErrorf("unknown config key in override: %s", key)
}
// Get current value to determine type for parsing
currentVal, found := l.config.Get(path)
if !found {
return fmtErrorf("failed to get current value for '%s'", key)
}
// Parse according to type
var parsedValue interface{}
var parseErr error
@ -114,19 +108,16 @@ func (l *Logger) InitWithDefaults(overrides ...string) error {
return fmtErrorf("invalid value format for '%s': %w", key, parseErr)
}
// Validate the parsed value
if err := validateConfigValue(keyLower, parsedValue); err != nil {
return fmtErrorf("invalid value for '%s': %w", key, err)
}
// Update config with new value
err = l.config.Set(path, parsedValue)
if err != nil {
return fmtErrorf("failed to update config value for '%s': %w", key, err)
}
}
// Apply configuration and reconfigure logger components
return l.applyAndReconfigureLocked()
}
@ -134,35 +125,29 @@ func (l *Logger) InitWithDefaults(overrides ...string) error {
// If no timeout is provided, uses a default of 2x flush interval
func (l *Logger) Shutdown(timeout ...time.Duration) error {
// Ensure shutdown runs only once
if !l.state.ShutdownCalled.CompareAndSwap(false, true) {
return nil
}
// Prevent new logs from being processed or sent
l.state.LoggerDisabled.Store(true)
// If the logger was never initialized, there's nothing to shut down
if !l.state.IsInitialized.Load() {
l.state.ShutdownCalled.Store(false) // Allow potential future init/shutdown cycle
l.state.ShutdownCalled.Store(false)
l.state.LoggerDisabled.Store(false)
l.state.ProcessorExited.Store(true) // Mark as not running
l.state.ProcessorExited.Store(true)
return nil
}
// Signal the processor goroutine to stop by closing its channel
l.initMu.Lock()
ch := l.getCurrentLogChannel()
closedChan := make(chan logRecord) // Create a dummy closed channel
closedChan := make(chan logRecord)
close(closedChan)
l.state.ActiveLogChannel.Store(closedChan) // Point producers to the dummy channel
// Close the actual channel the processor is reading from
l.state.ActiveLogChannel.Store(closedChan)
if ch != closedChan {
close(ch)
}
l.initMu.Unlock()
// Determine the effective timeout, if timeout is zero or negative, use a default based on flush interval
var effectiveTimeout time.Duration
if len(timeout) > 0 {
effectiveTimeout = timeout[0]
@ -172,42 +157,35 @@ func (l *Logger) Shutdown(timeout ...time.Duration) error {
effectiveTimeout = 2 * time.Duration(flushMs) * time.Millisecond
}
// Wait for the processor goroutine to signal its exit, or until the timeout
deadline := time.Now().Add(effectiveTimeout)
pollInterval := 10 * time.Millisecond // Check status periodically
pollInterval := 10 * time.Millisecond // Reasonable check period
processorCleanlyExited := false
for time.Now().Before(deadline) {
if l.state.ProcessorExited.Load() {
processorCleanlyExited = true
break // Processor finished cleanly
break
}
time.Sleep(pollInterval)
}
// Mark the logger as uninitialized
l.state.IsInitialized.Store(false)
// Sync and close the current log file
var finalErr error
cfPtr := l.state.CurrentFile.Load()
if cfPtr != nil {
if currentLogFile, ok := cfPtr.(*os.File); ok && currentLogFile != nil {
// Attempt to sync data to disk
if err := currentLogFile.Sync(); err != nil {
syncErr := fmtErrorf("failed to sync log file '%s' during shutdown: %w", currentLogFile.Name(), err)
finalErr = combineErrors(finalErr, syncErr)
}
// Attempt to close the file descriptor
if err := currentLogFile.Close(); err != nil {
closeErr := fmtErrorf("failed to close log file '%s' during shutdown: %w", currentLogFile.Name(), err)
finalErr = combineErrors(finalErr, closeErr)
}
// Clear the atomic reference to the file
l.state.CurrentFile.Store((*os.File)(nil))
}
}
// Report timeout error if processor didn't exit cleanly
if !processorCleanlyExited {
timeoutErr := fmtErrorf("logger processor did not exit within timeout (%v)", effectiveTimeout)
finalErr = combineErrors(finalErr, timeoutErr)
@ -218,7 +196,6 @@ func (l *Logger) Shutdown(timeout ...time.Duration) error {
// Flush explicitly triggers a sync of the current log file buffer to disk and waits for completion or timeout.
func (l *Logger) Flush(timeout time.Duration) error {
// Prevent concurrent flushes overwhelming the processor or channel
l.state.flushMutex.Lock()
defer l.state.flushMutex.Unlock()
@ -237,10 +214,9 @@ func (l *Logger) Flush(timeout time.Duration) error {
return fmtErrorf("failed to send flush request to processor (possible deadlock or high load)")
}
// Wait for the processor to signal completion or timeout
select {
case <-confirmChan:
return nil // Flush completed successfully
return nil
case <-time.After(timeout):
return fmtErrorf("timeout waiting for flush confirmation (%v)", timeout)
}