starlog/lifecycle.go

134 lines
2.8 KiB
Go
Raw Permalink Normal View History

2026-03-19 16:37:57 +08:00
package starlog
import (
"context"
"fmt"
"io"
"time"
)
type sinkSyncer interface {
Sync() error
}
type writerSyncer interface {
Sync() error
}
func mergeLifecycleError(current error, next error) error {
if next == nil {
return current
}
if current == nil {
return next
}
return fmt.Errorf("%v; %w", current, next)
}
func WaitAsyncDrain(ctx context.Context) error {
if ctx == nil {
ctx = context.Background()
}
for {
stackMu.Lock()
current := stacks
started := stackStarted
stackMu.Unlock()
if !started || current == nil || current.Len() == 0 {
return nil
}
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(5 * time.Millisecond):
}
}
}
func (logger *StarLogger) Flush() error {
if logger == nil || logger.logcore == nil {
return nil
}
logger.logcore.mu.Lock()
previousSwitching := logger.logcore.switching
logger.logcore.switching = false
logger.logcore.writePendingLocked()
logger.logcore.switching = previousSwitching
logger.logcore.mu.Unlock()
return nil
}
func (logger *StarLogger) Sync() error {
if logger == nil || logger.logcore == nil {
return nil
}
if err := logger.Flush(); err != nil {
return err
}
logger.logcore.mu.Lock()
sink := logger.logcore.sink
writer := logger.logcore.output
logger.logcore.mu.Unlock()
var err error
if sink != nil {
if syncer, ok := sink.(sinkSyncer); ok {
err = mergeLifecycleError(err, syncer.Sync())
}
return err
}
if writer != nil {
if syncer, ok := writer.(writerSyncer); ok {
err = mergeLifecycleError(err, syncer.Sync())
}
}
return err
}
// Close flushes/syncs and closes archive-managed file/sink/writer resources.
// It does not wait for async handler queue; use Shutdown for graceful app exit.
func (logger *StarLogger) Close() error {
if logger == nil || logger.logcore == nil {
return nil
}
var err error
StopArchive(logger)
err = mergeLifecycleError(err, logger.Sync())
err = mergeLifecycleError(err, CloseLogFile(logger))
logger.logcore.mu.Lock()
sink := logger.logcore.sink
writer := logger.logcore.output
entryHandler := logger.logcore.entryHandler
logger.logcore.mu.Unlock()
if sink != nil {
err = mergeLifecycleError(err, sink.Close())
} else if writer != nil {
if closer, ok := writer.(io.Closer); ok {
err = mergeLifecycleError(err, closer.Close())
}
}
if entryHandler != nil {
if closer, ok := entryHandler.(interface{ Close() error }); ok {
err = mergeLifecycleError(err, closer.Close())
}
}
logger.StopWrite()
return err
}
func (logger *StarLogger) Shutdown(ctx context.Context) error {
if logger == nil || logger.logcore == nil {
return nil
}
var err error
err = mergeLifecycleError(err, logger.Flush())
err = mergeLifecycleError(err, WaitAsyncDrain(ctx))
StopStacks()
err = mergeLifecycleError(err, logger.Close())
return err
}