| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- package log
- import (
- "io"
- "sync"
- "sync/atomic"
- )
- // SwapLogger wraps another logger that may be safely replaced while other
- // goroutines use the SwapLogger concurrently. The zero value for a SwapLogger
- // will discard all log events without error.
- //
- // SwapLogger serves well as a package global logger that can be changed by
- // importers.
- type SwapLogger struct {
- logger atomic.Value
- }
- type loggerStruct struct {
- Logger
- }
- // Log implements the Logger interface by forwarding keyvals to the currently
- // wrapped logger. It does not log anything if the wrapped logger is nil.
- func (l *SwapLogger) Log(keyvals ...interface{}) error {
- s, ok := l.logger.Load().(loggerStruct)
- if !ok || s.Logger == nil {
- return nil
- }
- return s.Log(keyvals...)
- }
- // Swap replaces the currently wrapped logger with logger. Swap may be called
- // concurrently with calls to Log from other goroutines.
- func (l *SwapLogger) Swap(logger Logger) {
- l.logger.Store(loggerStruct{logger})
- }
- // NewSyncWriter returns a new writer that is safe for concurrent use by
- // multiple goroutines. Writes to the returned writer are passed on to w. If
- // another write is already in progress, the calling goroutine blocks until
- // the writer is available.
- //
- // If w implements the following interface, so does the returned writer.
- //
- // interface {
- // Fd() uintptr
- // }
- func NewSyncWriter(w io.Writer) io.Writer {
- switch w := w.(type) {
- case fdWriter:
- return &fdSyncWriter{fdWriter: w}
- default:
- return &syncWriter{Writer: w}
- }
- }
- // syncWriter synchronizes concurrent writes to an io.Writer.
- type syncWriter struct {
- sync.Mutex
- io.Writer
- }
- // Write writes p to the underlying io.Writer. If another write is already in
- // progress, the calling goroutine blocks until the syncWriter is available.
- func (w *syncWriter) Write(p []byte) (n int, err error) {
- w.Lock()
- n, err = w.Writer.Write(p)
- w.Unlock()
- return n, err
- }
- // fdWriter is an io.Writer that also has an Fd method. The most common
- // example of an fdWriter is an *os.File.
- type fdWriter interface {
- io.Writer
- Fd() uintptr
- }
- // fdSyncWriter synchronizes concurrent writes to an fdWriter.
- type fdSyncWriter struct {
- sync.Mutex
- fdWriter
- }
- // Write writes p to the underlying io.Writer. If another write is already in
- // progress, the calling goroutine blocks until the fdSyncWriter is available.
- func (w *fdSyncWriter) Write(p []byte) (n int, err error) {
- w.Lock()
- n, err = w.fdWriter.Write(p)
- w.Unlock()
- return n, err
- }
- // syncLogger provides concurrent safe logging for another Logger.
- type syncLogger struct {
- mu sync.Mutex
- logger Logger
- }
- // NewSyncLogger returns a logger that synchronizes concurrent use of the
- // wrapped logger. When multiple goroutines use the SyncLogger concurrently
- // only one goroutine will be allowed to log to the wrapped logger at a time.
- // The other goroutines will block until the logger is available.
- func NewSyncLogger(logger Logger) Logger {
- return &syncLogger{logger: logger}
- }
- // Log logs keyvals to the underlying Logger. If another log is already in
- // progress, the calling goroutine blocks until the syncLogger is available.
- func (l *syncLogger) Log(keyvals ...interface{}) error {
- l.mu.Lock()
- err := l.logger.Log(keyvals...)
- l.mu.Unlock()
- return err
- }
|