github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/go-kit/kit/log/sync.go (about) 1 package log 2 3 import ( 4 "io" 5 "sync" 6 "sync/atomic" 7 ) 8 9 // SwapLogger wraps another logger that may be safely replaced while other 10 // goroutines use the SwapLogger concurrently. The zero value for a SwapLogger 11 // will discard all log events without error. 12 // 13 // SwapLogger serves well as a package global logger that can be changed by 14 // importers. 15 type SwapLogger struct { 16 logger atomic.Value 17 } 18 19 type loggerStruct struct { 20 Logger 21 } 22 23 // Log implements the Logger interface by forwarding keyvals to the currently 24 // wrapped logger. It does not log anything if the wrapped logger is nil. 25 func (l *SwapLogger) Log(keyvals ...interface{}) error { 26 s, ok := l.logger.Load().(loggerStruct) 27 if !ok || s.Logger == nil { 28 return nil 29 } 30 return s.Log(keyvals...) 31 } 32 33 // Swap replaces the currently wrapped logger with logger. Swap may be called 34 // concurrently with calls to Log from other goroutines. 35 func (l *SwapLogger) Swap(logger Logger) { 36 l.logger.Store(loggerStruct{logger}) 37 } 38 39 // NewSyncWriter returns a new writer that is safe for concurrent use by 40 // multiple goroutines. Writes to the returned writer are passed on to w. If 41 // another write is already in progress, the calling goroutine blocks until 42 // the writer is available. 43 // 44 // If w implements the following interface, so does the returned writer. 45 // 46 // interface { 47 // Fd() uintptr 48 // } 49 func NewSyncWriter(w io.Writer) io.Writer { 50 switch w := w.(type) { 51 case fdWriter: 52 return &fdSyncWriter{fdWriter: w} 53 default: 54 return &syncWriter{Writer: w} 55 } 56 } 57 58 // syncWriter synchronizes concurrent writes to an io.Writer. 59 type syncWriter struct { 60 sync.Mutex 61 io.Writer 62 } 63 64 // Write writes p to the underlying io.Writer. If another write is already in 65 // progress, the calling goroutine blocks until the syncWriter is available. 66 func (w *syncWriter) Write(p []byte) (n int, err error) { 67 w.Lock() 68 n, err = w.Writer.Write(p) 69 w.Unlock() 70 return n, err 71 } 72 73 // fdWriter is an io.Writer that also has an Fd method. The most common 74 // example of an fdWriter is an *os.File. 75 type fdWriter interface { 76 io.Writer 77 Fd() uintptr 78 } 79 80 // fdSyncWriter synchronizes concurrent writes to an fdWriter. 81 type fdSyncWriter struct { 82 sync.Mutex 83 fdWriter 84 } 85 86 // Write writes p to the underlying io.Writer. If another write is already in 87 // progress, the calling goroutine blocks until the fdSyncWriter is available. 88 func (w *fdSyncWriter) Write(p []byte) (n int, err error) { 89 w.Lock() 90 n, err = w.fdWriter.Write(p) 91 w.Unlock() 92 return n, err 93 } 94 95 // syncLogger provides concurrent safe logging for another Logger. 96 type syncLogger struct { 97 mu sync.Mutex 98 logger Logger 99 } 100 101 // NewSyncLogger returns a logger that synchronizes concurrent use of the 102 // wrapped logger. When multiple goroutines use the SyncLogger concurrently 103 // only one goroutine will be allowed to log to the wrapped logger at a time. 104 // The other goroutines will block until the logger is available. 105 func NewSyncLogger(logger Logger) Logger { 106 return &syncLogger{logger: logger} 107 } 108 109 // Log logs keyvals to the underlying Logger. If another log is already in 110 // progress, the calling goroutine blocks until the syncLogger is available. 111 func (l *syncLogger) Log(keyvals ...interface{}) error { 112 l.mu.Lock() 113 err := l.logger.Log(keyvals...) 114 l.mu.Unlock() 115 return err 116 }