v0.1.9 kv flag added, unix and nofs build tags, heartbeat and rotation filename and test update
This commit is contained in:
@@ -7,56 +7,27 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// getCurrentLogChannel safely retrieves the current log channel
|
||||
// getCurrentLogChannel returns the active record channel, nil when detached
|
||||
func (l *Logger) getCurrentLogChannel() chan logRecord {
|
||||
chVal := l.state.ActiveLogChannel.Load()
|
||||
// No defensive nil check required in correct use of initialized logger
|
||||
return chVal.(chan logRecord)
|
||||
ch, _ := l.state.ActiveLogChannel.Load().(chan logRecord)
|
||||
return ch
|
||||
}
|
||||
|
||||
// getFlags from config
|
||||
// getFlags returns the cached default record flags
|
||||
func (l *Logger) getFlags() int64 {
|
||||
var flags int64 = 0
|
||||
cfg := l.getConfig()
|
||||
|
||||
if cfg.ShowLevel {
|
||||
flags |= FlagShowLevel
|
||||
}
|
||||
if cfg.ShowTimestamp {
|
||||
flags |= FlagShowTimestamp
|
||||
}
|
||||
return flags
|
||||
return l.state.Flags.Load()
|
||||
}
|
||||
|
||||
// sendLogRecord handles safe sending to the active channel
|
||||
// sendLogRecord queues a record without blocking. The channel is never closed,
|
||||
// so no recovery is needed: a detached (nil) channel takes the default branch.
|
||||
func (l *Logger) sendLogRecord(record logRecord) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// A panic is only expected when a race condition occurs during shutdown
|
||||
if err, ok := r.(error); ok && err.Error() == "send on closed channel" {
|
||||
// Expected race condition between logging and shutdown
|
||||
l.handleFailedSend()
|
||||
} else {
|
||||
// Unexpected panic, re-throw to surface
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if l.state.ShutdownCalled.Load() ||
|
||||
l.state.LoggerDisabled.Load() ||
|
||||
!l.state.Started.Load() {
|
||||
// Process drops even if logger is disabled or shutting down
|
||||
if l.state.LoggerDisabled.Load() {
|
||||
l.handleFailedSend()
|
||||
return
|
||||
}
|
||||
|
||||
ch := l.getCurrentLogChannel()
|
||||
|
||||
// Non-blocking send
|
||||
select {
|
||||
case ch <- record:
|
||||
// Success
|
||||
default:
|
||||
l.handleFailedSend()
|
||||
}
|
||||
@@ -68,59 +39,79 @@ func (l *Logger) handleFailedSend() {
|
||||
l.state.TotalDroppedLogs.Add(1) // Total counter
|
||||
}
|
||||
|
||||
// log handles the core logging logic
|
||||
func (l *Logger) log(flags int64, level int64, depth int64, args ...any) {
|
||||
// State checks
|
||||
if !l.state.IsInitialized.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
if !l.state.Started.Load() {
|
||||
// Log to internal error channel if configured
|
||||
cfg := l.getConfig()
|
||||
if cfg.InternalErrorsToStderr {
|
||||
l.internalLog("warning - logger not started, dropping log entry\n")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Discard or proceed based on level
|
||||
cfg := l.getConfig()
|
||||
if level < cfg.Level {
|
||||
return
|
||||
}
|
||||
|
||||
// Get trace info from runtime
|
||||
// emit builds and queues a record; the caller has already passed the level gate
|
||||
func (l *Logger) emit(ctx Context, flags, level, depth int64, args []any) {
|
||||
// Depth filter hard-coded based on call stack of current package design
|
||||
var trace string
|
||||
if depth > 0 {
|
||||
const skipTrace = 3 // log.Info -> log -> getTrace (Adjust if call stack changes)
|
||||
const skipTrace = 3 // Logger.Info -> emit -> getTrace
|
||||
trace = getTrace(depth, skipTrace)
|
||||
}
|
||||
|
||||
record := logRecord{
|
||||
l.sendLogRecord(logRecord{
|
||||
Ctx: ctx,
|
||||
Flags: flags,
|
||||
TimeStamp: time.Now(),
|
||||
Level: level,
|
||||
Trace: trace,
|
||||
Args: args,
|
||||
}
|
||||
l.sendLogRecord(record)
|
||||
})
|
||||
}
|
||||
|
||||
// internalLog handles writing internal logger diagnostics to stderr if enabled
|
||||
// internalLog reports logger diagnostics to the registered handler, or to
|
||||
// stderr when configured. Hosts owning a terminal must register a handler.
|
||||
func (l *Logger) internalLog(format string, args ...any) {
|
||||
// Check if internal error reporting is enabled
|
||||
cfg := l.getConfig()
|
||||
if !cfg.InternalErrorsToStderr {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure consistent "log: " prefix
|
||||
if !strings.HasPrefix(format, "log: ") {
|
||||
format = "log: " + format
|
||||
}
|
||||
|
||||
// Write to stderr
|
||||
if h := l.errHandler.Load(); h != nil {
|
||||
(*h)(strings.TrimRight(fmt.Sprintf(format, args...), "\n"))
|
||||
return
|
||||
}
|
||||
|
||||
if !l.getConfig().InternalErrorsToStderr {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// // log handles the core logging logic
|
||||
// func (l *Logger) log(flags int64, level int64, depth int64, args ...any) {
|
||||
// // State checks
|
||||
// if !l.state.IsInitialized.Load() {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if !l.state.Started.Load() {
|
||||
// // Log to internal error channel if configured
|
||||
// cfg := l.getConfig()
|
||||
// if cfg.InternalErrorsToStderr {
|
||||
// l.internalLog("warning - logger not started, dropping log entry\n")
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Discard or proceed based on level
|
||||
// cfg := l.getConfig()
|
||||
// if level < cfg.Level {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Get trace info from runtime
|
||||
// // Depth filter hard-coded based on call stack of current package design
|
||||
// var trace string
|
||||
// if depth > 0 {
|
||||
// const skipTrace = 3 // log.Info -> log -> getTrace (Adjust if call stack changes)
|
||||
// trace = getTrace(depth, skipTrace)
|
||||
// }
|
||||
//
|
||||
// record := logRecord{
|
||||
// Flags: flags,
|
||||
// TimeStamp: time.Now(),
|
||||
// Level: level,
|
||||
// Trace: trace,
|
||||
// Args: args,
|
||||
// }
|
||||
// l.sendLogRecord(record)
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user