134 lines
2.8 KiB
Go
134 lines
2.8 KiB
Go
|
|
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
|
||
|
|
}
|