mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-15 16:30:55 +01:00
7f4fb34182
It is better developing vmctl tool in VictoriaMetrics repository, so it could be released together with the rest of vmutils tools such as vmalert, vmagent, vmbackup, vmrestore and vmauth.
117 lines
3.2 KiB
Go
117 lines
3.2 KiB
Go
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
|
|
}
|