Add SwapLogger.
Chris Hines
8 years ago
2 | 2 |
// The fundamental interface is Logger. Loggers create log events from
|
3 | 3 |
// key/value data.
|
4 | 4 |
package log
|
|
5 |
|
|
6 |
import "sync/atomic"
|
5 | 7 |
|
6 | 8 |
// Logger is the fundamental interface for all log operations. Implementations
|
7 | 9 |
// must be safe for concurrent use by multiple goroutines. Log creates a log
|
|
57 | 59 |
func (f LoggerFunc) Log(keyvals ...interface{}) error {
|
58 | 60 |
return f(keyvals...)
|
59 | 61 |
}
|
|
62 |
|
|
63 |
// SwapLogger wraps another logger that may be safely replaced while other
|
|
64 |
// goroutines use the SwapLogger concurrently.
|
|
65 |
type SwapLogger struct {
|
|
66 |
logger atomic.Value
|
|
67 |
}
|
|
68 |
|
|
69 |
type loggerStruct struct {
|
|
70 |
Logger
|
|
71 |
}
|
|
72 |
|
|
73 |
// NewSwapLogger returns a pointer to a new SwapLogger that wraps logger.
|
|
74 |
func NewSwapLogger(logger Logger) *SwapLogger {
|
|
75 |
l := &SwapLogger{}
|
|
76 |
l.Swap(logger)
|
|
77 |
return l
|
|
78 |
}
|
|
79 |
|
|
80 |
// Log implements the Logger interface by calling Log on the currently wrapped
|
|
81 |
// logger.
|
|
82 |
func (l *SwapLogger) Log(keyvals ...interface{}) error {
|
|
83 |
return l.logger.Load().(loggerStruct).Log(keyvals...)
|
|
84 |
}
|
|
85 |
|
|
86 |
// Swap replaces the currently wrapped logger with logger. Swap may be called
|
|
87 |
// concurrently with calls to Log from other goroutines.
|
|
88 |
func (l *SwapLogger) Swap(logger Logger) {
|
|
89 |
l.logger.Store(loggerStruct{logger})
|
|
90 |
}
|
110 | 110 |
logger.Log("k", "v")
|
111 | 111 |
}
|
112 | 112 |
}
|
|
113 |
|
|
114 |
func TestSwapLogger(t *testing.T) {
|
|
115 |
buf := &bytes.Buffer{}
|
|
116 |
json := log.NewJSONLogger(buf)
|
|
117 |
logger := log.NewSwapLogger(json)
|
|
118 |
|
|
119 |
if err := logger.Log("k", "v"); err != nil {
|
|
120 |
t.Error(err)
|
|
121 |
}
|
|
122 |
if got, want := buf.String(), `{"k":"v"}`+"\n"; got != want {
|
|
123 |
t.Errorf("got %v, want %v", got, want)
|
|
124 |
}
|
|
125 |
|
|
126 |
buf.Reset()
|
|
127 |
prefix := log.NewPrefixLogger(buf)
|
|
128 |
logger.Swap(prefix)
|
|
129 |
|
|
130 |
if err := logger.Log("k", "v"); err != nil {
|
|
131 |
t.Error(err)
|
|
132 |
}
|
|
133 |
if got, want := buf.String(), "k=v\n"; got != want {
|
|
134 |
t.Errorf("got %v, want %v", got, want)
|
|
135 |
}
|
|
136 |
}
|
|
137 |
|
|
138 |
func TestSwapLoggerConcurrency(t *testing.T) {
|
|
139 |
testConcurrency(t, log.NewSwapLogger(discard))
|
|
140 |
}
|