sync.go 3.2 KB

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