e3.1.2 Changed output stdout to console for clarity.

This commit is contained in:
2025-09-29 04:47:48 -04:00
parent 2234123f59
commit d58b61067f
11 changed files with 149 additions and 41 deletions

View File

@ -94,12 +94,6 @@ func (b *Builder) MaxSizeMB(size int64) *Builder {
return b
}
// EnableStdout enables mirroring logs to stdout/stderr.
func (b *Builder) EnableStdout(enable bool) *Builder {
b.cfg.EnableStdout = enable
return b
}
// DisableFile disables file output entirely.
func (b *Builder) DisableFile(disable bool) *Builder {
b.cfg.DisableFile = disable
@ -118,6 +112,120 @@ func (b *Builder) HeartbeatIntervalS(interval int64) *Builder {
return b
}
// ShowTimestamp sets whether to show timestamps in logs.
func (b *Builder) ShowTimestamp(show bool) *Builder {
b.cfg.ShowTimestamp = show
return b
}
// ShowLevel sets whether to show log levels.
func (b *Builder) ShowLevel(show bool) *Builder {
b.cfg.ShowLevel = show
return b
}
// TimestampFormat sets the timestamp format string.
func (b *Builder) TimestampFormat(format string) *Builder {
b.cfg.TimestampFormat = format
return b
}
// MaxTotalSizeKB sets the maximum total size of all log files in KB.
func (b *Builder) MaxTotalSizeKB(size int64) *Builder {
b.cfg.MaxTotalSizeKB = size
return b
}
// MaxTotalSizeMB sets the maximum total size of all log files in MB. Convenience.
func (b *Builder) MaxTotalSizeMB(size int64) *Builder {
b.cfg.MaxTotalSizeKB = size * 1000
return b
}
// MinDiskFreeKB sets the minimum required free disk space in KB.
func (b *Builder) MinDiskFreeKB(size int64) *Builder {
b.cfg.MinDiskFreeKB = size
return b
}
// MinDiskFreeMB sets the minimum required free disk space in MB. Convenience.
func (b *Builder) MinDiskFreeMB(size int64) *Builder {
b.cfg.MinDiskFreeKB = size * 1000
return b
}
// FlushIntervalMs sets the flush interval in milliseconds.
func (b *Builder) FlushIntervalMs(interval int64) *Builder {
b.cfg.FlushIntervalMs = interval
return b
}
// TraceDepth sets the default trace depth for stack traces.
func (b *Builder) TraceDepth(depth int64) *Builder {
b.cfg.TraceDepth = depth
return b
}
// RetentionPeriodHrs sets the log retention period in hours.
func (b *Builder) RetentionPeriodHrs(hours float64) *Builder {
b.cfg.RetentionPeriodHrs = hours
return b
}
// RetentionCheckMins sets the retention check interval in minutes.
func (b *Builder) RetentionCheckMins(mins float64) *Builder {
b.cfg.RetentionCheckMins = mins
return b
}
// DiskCheckIntervalMs sets the disk check interval in milliseconds.
func (b *Builder) DiskCheckIntervalMs(interval int64) *Builder {
b.cfg.DiskCheckIntervalMs = interval
return b
}
// EnableAdaptiveInterval enables adaptive disk check intervals.
func (b *Builder) EnableAdaptiveInterval(enable bool) *Builder {
b.cfg.EnableAdaptiveInterval = enable
return b
}
// EnablePeriodicSync enables periodic file sync.
func (b *Builder) EnablePeriodicSync(enable bool) *Builder {
b.cfg.EnablePeriodicSync = enable
return b
}
// MinCheckIntervalMs sets the minimum disk check interval in milliseconds.
func (b *Builder) MinCheckIntervalMs(interval int64) *Builder {
b.cfg.MinCheckIntervalMs = interval
return b
}
// MaxCheckIntervalMs sets the maximum disk check interval in milliseconds.
func (b *Builder) MaxCheckIntervalMs(interval int64) *Builder {
b.cfg.MaxCheckIntervalMs = interval
return b
}
// ConsoleTarget sets the console output target ("stdout", "stderr", or "split").
func (b *Builder) ConsoleTarget(target string) *Builder {
b.cfg.ConsoleTarget = target
return b
}
// InternalErrorsToStderr sets whether to write internal errors to stderr.
func (b *Builder) InternalErrorsToStderr(enable bool) *Builder {
b.cfg.InternalErrorsToStderr = enable
return b
}
// EnableConsole enables mirroring logs to console.
func (b *Builder) EnableConsole(enable bool) *Builder {
b.cfg.EnableConsole = enable
return b
}
// Example usage:
// logger, err := log.NewBuilder().
//
@ -125,7 +233,7 @@ func (b *Builder) HeartbeatIntervalS(interval int64) *Builder {
// LevelString("debug").
// Format("json").
// BufferSize(4096).
// EnableStdout(true).
// EnableConsole(true).
// Build()
//
// if err == nil {

View File

@ -20,7 +20,7 @@ func TestBuilder_Build(t *testing.T) {
LevelString("debug").
Format("json").
BufferSize(2048).
EnableStdout(true).
EnableConsole(true).
MaxSizeMB(10).
HeartbeatLevel(2).
Build()
@ -43,7 +43,7 @@ func TestBuilder_Build(t *testing.T) {
assert.Equal(t, LevelDebug, cfg.Level)
assert.Equal(t, "json", cfg.Format)
assert.Equal(t, int64(2048), cfg.BufferSize)
assert.True(t, cfg.EnableStdout, "EnableStdout should be true")
assert.True(t, cfg.EnableConsole, "EnableConsole should be true")
assert.Equal(t, int64(10*1000), cfg.MaxSizeKB)
assert.Equal(t, int64(2), cfg.HeartbeatLevel)
})

View File

@ -46,9 +46,9 @@ type Config struct {
HeartbeatIntervalS int64 `toml:"heartbeat_interval_s"` // Interval seconds for heartbeat
// Stdout/console output settings
EnableStdout bool `toml:"enable_stdout"` // Mirror logs to stdout/stderr
StdoutTarget string `toml:"stdout_target"` // "stdout" or "stderr"
DisableFile bool `toml:"disable_file"` // Disable file output entirely
EnableConsole bool `toml:"enable_console"` // Mirror logs to stdout/stderr
ConsoleTarget string `toml:"console_target"` // "stdout" or "stderr"
DisableFile bool `toml:"disable_file"` // Disable file output entirely
// Internal error handling
InternalErrorsToStderr bool `toml:"internal_errors_to_stderr"` // Write internal errors to stderr
@ -92,9 +92,9 @@ var defaultConfig = Config{
HeartbeatIntervalS: 60,
// Stdout settings
EnableStdout: false,
StdoutTarget: "stdout",
DisableFile: false,
EnableConsole: false,
ConsoleTarget: "stdout",
DisableFile: false,
// Internal error handling
InternalErrorsToStderr: false,
@ -131,8 +131,8 @@ func (c *Config) Validate() error {
return fmtErrorf("timestamp_format cannot be empty")
}
if c.StdoutTarget != "stdout" && c.StdoutTarget != "stderr" && c.StdoutTarget != "split" {
return fmtErrorf("invalid stdout_target: '%s' (use stdout, stderr, or split)", c.StdoutTarget)
if c.ConsoleTarget != "stdout" && c.ConsoleTarget != "stderr" && c.ConsoleTarget != "split" {
return fmtErrorf("invalid console_target: '%s' (use stdout, stderr, or split)", c.ConsoleTarget)
}
// Numeric validations
@ -315,15 +315,15 @@ func applyConfigField(cfg *Config, key, value string) error {
}
cfg.HeartbeatIntervalS = intVal
// Stdout/console output settings
case "enable_stdout":
// Console output settings
case "enable_console":
boolVal, err := strconv.ParseBool(value)
if err != nil {
return fmtErrorf("invalid boolean value for enable_stdout '%s': %w", value, err)
return fmtErrorf("invalid boolean value for enable_console '%s': %w", value, err)
}
cfg.EnableStdout = boolVal
case "stdout_target":
cfg.StdoutTarget = value
cfg.EnableConsole = boolVal
case "console_target":
cfg.ConsoleTarget = value
case "disable_file":
boolVal, err := strconv.ParseBool(value)
if err != nil {

View File

@ -84,8 +84,8 @@ func TestConfigValidate(t *testing.T) {
},
{
name: "invalid stdout target",
modify: func(c *Config) { c.StdoutTarget = "invalid" },
wantError: "invalid stdout_target",
modify: func(c *Config) { c.ConsoleTarget = "invalid" },
wantError: "invalid console_target",
},
{
name: "min > max check interval",

View File

@ -286,7 +286,7 @@ builder := compat.NewBuilder().
"format=txt", // Human-readable
"level=-4", // Debug level
"trace_depth=3", // Include traces
"enable_stdout=true", // Console output
"enable_console=true", // Console output
"flush_interval_ms=50", // Quick feedback
)
```
@ -297,7 +297,7 @@ builder := compat.NewBuilder().
builder := compat.NewBuilder().
WithOptions(
"disable_file=true", // No files
"enable_stdout=true", // Console only
"enable_console=true", // Console only
"format=json", // For aggregators
"level=0", // Info and above
)

View File

@ -28,7 +28,7 @@ All builder methods return `*ConfigBuilder` for chaining. Errors are accumulated
| `Format(format string)` | `format`: Output format | Sets format ("txt", "json", "raw") |
| `BufferSize(size int64)` | `size`: Buffer size | Sets channel buffer size |
| `MaxSizeKB(size int64)` | `size`: Size in MB | Sets max file size |
| `EnableStdout(enable bool)` | `enable`: Boolean | Enables console output |
| `EnableConsole(enable bool)` | `enable`: Boolean | Enables console output |
| `DisableFile(disable bool)` | `disable`: Boolean | Disables file output |
| `HeartbeatLevel(level int64)` | `level`: 0-3 | Sets monitoring level |

View File

@ -60,11 +60,11 @@ logger.Info("info txt log record written to /var/log/myapp.txt")
|-----------|------|-------------|---------|
| `show_timestamp` | `bool` | Include timestamps in log entries | `true` |
| `show_level` | `bool` | Include log level in entries | `true` |
| `enable_stdout` | `bool` | Mirror logs to stdout/stderr | `false` |
| `stdout_target` | `string` | Console target: `"stdout"`, `"stderr"`, or `"split"` | `"stdout"` |
| `enable_console` | `bool` | Mirror logs to stdout/stderr | `false` |
| `console_target` | `string` | Console target: `"stdout"`, `"stderr"`, or `"split"` | `"stdout"` |
| `disable_file` | `bool` | Disable file output (console-only) | `false` |
**Note:** When `stdout_target="split"`, INFO/DEBUG logs go to stdout while WARN/ERROR logs go to stderr.
**Note:** When `console_target="split"`, INFO/DEBUG logs go to stdout while WARN/ERROR logs go to stderr.
### Performance Tuning

View File

@ -22,7 +22,7 @@ func TestFullLifecycle(t *testing.T) {
Format("json").
MaxSizeKB(1).
BufferSize(1000).
EnableStdout(false).
EnableConsole(false).
HeartbeatLevel(1).
HeartbeatIntervalS(2).
Build()
@ -60,7 +60,7 @@ func TestFullLifecycle(t *testing.T) {
logger.InfoTrace(2, "trace info")
// Apply runtime override
err = logger.ApplyConfigString("enable_stdout=true", "stdout_target=stderr")
err = logger.ApplyConfigString("enable_console=true", "console_target=stderr")
require.NoError(t, err)
// More logging after reconfiguration

View File

@ -430,9 +430,9 @@ func (l *Logger) applyConfig(cfg *Config) error {
}
// Setup stdout writer based on config
if cfg.EnableStdout {
if cfg.EnableConsole {
var writer io.Writer
if cfg.StdoutTarget == "stderr" {
if cfg.ConsoleTarget == "stderr" {
writer = os.Stderr
} else {
writer = os.Stdout

View File

@ -89,12 +89,12 @@ func TestApplyConfigString(t *testing.T) {
{
name: "boolean values",
configString: []string{
"enable_stdout=true",
"enable_console=true",
"disable_file=false",
"show_timestamp=false",
},
verify: func(t *testing.T, cfg *Config) {
assert.True(t, cfg.EnableStdout)
assert.True(t, cfg.EnableConsole)
assert.False(t, cfg.DisableFile)
assert.False(t, cfg.ShowTimestamp)
},
@ -265,7 +265,7 @@ func TestLoggerStdoutMirroring(t *testing.T) {
cfg := DefaultConfig()
cfg.Directory = t.TempDir()
cfg.EnableStdout = true
cfg.EnableConsole = true
cfg.DisableFile = true
err := logger.ApplyConfig(cfg)

View File

@ -115,12 +115,12 @@ func (l *Logger) processLogRecord(record logRecord) int64 {
dataLen := int64(len(data))
// Mirror to stdout if enabled
enableStdout := c.EnableStdout
if enableStdout {
enableConsole := c.EnableConsole
if enableConsole {
if s := l.state.StdoutWriter.Load(); s != nil {
if sinkWrapper, ok := s.(*sink); ok && sinkWrapper != nil {
// Handle split mode
if c.StdoutTarget == "split" {
if c.ConsoleTarget == "split" {
if record.Level >= LevelWarn {
// Write WARN and ERROR to stderr
_, _ = os.Stderr.Write(data)