diff options
author | 2022-07-18 21:52:06 +0800 | |
---|---|---|
committer | 2022-07-18 09:52:06 -0400 | |
commit | edbe02c0f91f0a9dae27164ab87115d59e76882d (patch) | |
tree | 103a2bf5879f5974d207807f9b651207b5ee5657 /plugin | |
parent | 29f3dcfa10b45cc5a38c472c4d48d08d530e644e (diff) | |
download | coredns-edbe02c0f91f0a9dae27164ab87115d59e76882d.tar.gz coredns-edbe02c0f91f0a9dae27164ab87115d59e76882d.tar.zst coredns-edbe02c0f91f0a9dae27164ab87115d59e76882d.zip |
core: add log listeners for k8s_event plugin (#5451)
add log listener interface
Signed-off-by: xh4n3 <xyn1016@gmail.com>
Diffstat (limited to 'plugin')
-rw-r--r-- | plugin/pkg/log/listener.go | 142 | ||||
-rw-r--r-- | plugin/pkg/log/listener_test.go | 121 | ||||
-rw-r--r-- | plugin/pkg/log/plugin.go | 44 |
3 files changed, 299 insertions, 8 deletions
diff --git a/plugin/pkg/log/listener.go b/plugin/pkg/log/listener.go new file mode 100644 index 000000000..c1dda2cac --- /dev/null +++ b/plugin/pkg/log/listener.go @@ -0,0 +1,142 @@ +package log + +import ( + "sync" +) + +// Listener listens for all log prints of plugin loggers aka loggers with plugin name. +// When a plugin logger gets called, it should first call the same method in the Listener object. +// A usage example is, the external plugin k8s_event will replicate log prints to Kubernetes events. +type Listener interface { + Name() string + Debug(plugin string, v ...interface{}) + Debugf(plugin string, format string, v ...interface{}) + Info(plugin string, v ...interface{}) + Infof(plugin string, format string, v ...interface{}) + Warning(plugin string, v ...interface{}) + Warningf(plugin string, format string, v ...interface{}) + Error(plugin string, v ...interface{}) + Errorf(plugin string, format string, v ...interface{}) + Fatal(plugin string, v ...interface{}) + Fatalf(plugin string, format string, v ...interface{}) +} + +type listeners struct { + listeners []Listener + sync.RWMutex +} + +var ls *listeners + +func init() { + ls = &listeners{} + ls.listeners = make([]Listener, 0) +} + +// RegisterListener register a listener object. +func RegisterListener(new Listener) error { + ls.Lock() + defer ls.Unlock() + for k, l := range ls.listeners { + if l.Name() == new.Name() { + ls.listeners[k] = new + return nil + } + } + ls.listeners = append(ls.listeners, new) + return nil +} + +// DeregisterListener deregister a listener object. +func DeregisterListener(old Listener) error { + ls.Lock() + defer ls.Unlock() + for k, l := range ls.listeners { + if l.Name() == old.Name() { + ls.listeners = append(ls.listeners[:k], ls.listeners[k+1:]...) + return nil + } + } + return nil +} + +func (ls *listeners) debug(plugin string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Debug(plugin, v...) + } + ls.RUnlock() +} + +func (ls *listeners) debugf(plugin string, format string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Debugf(plugin, format, v...) + } + ls.RUnlock() +} + +func (ls *listeners) info(plugin string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Info(plugin, v...) + } + ls.RUnlock() + +} + +func (ls *listeners) infof(plugin string, format string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Infof(plugin, format, v...) + } + ls.RUnlock() +} + +func (ls *listeners) warning(plugin string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Warning(plugin, v...) + } + ls.RUnlock() +} + +func (ls *listeners) warningf(plugin string, format string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Warningf(plugin, format, v...) + } + ls.RUnlock() +} + +func (ls *listeners) error(plugin string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Error(plugin, v...) + } + ls.RUnlock() +} + +func (ls *listeners) errorf(plugin string, format string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Errorf(plugin, format, v...) + } + ls.RUnlock() +} + +func (ls *listeners) fatal(plugin string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Fatal(plugin, v...) + } + ls.RUnlock() +} + +func (ls *listeners) fatalf(plugin string, format string, v ...interface{}) { + ls.RLock() + for _, l := range ls.listeners { + l.Fatalf(plugin, format, v...) + } + ls.RUnlock() +} diff --git a/plugin/pkg/log/listener_test.go b/plugin/pkg/log/listener_test.go new file mode 100644 index 000000000..f050dad69 --- /dev/null +++ b/plugin/pkg/log/listener_test.go @@ -0,0 +1,121 @@ +package log + +import ( + "bytes" + golog "log" + "strings" + "testing" +) + +func TestRegisterAndDeregisterListener(t *testing.T) { + for _, name := range []string{"listener1", "listener2", "listener1"} { + err := RegisterListener(NewMockListener(name)) + if err != nil { + t.Errorf("RegsiterListener Error %s", err) + } + } + if len(ls.listeners) != 2 { + t.Errorf("Expected number of listeners to be %d, got %d", 2, len(ls.listeners)) + } + for _, name := range []string{"listener1", "listener2"} { + err := DeregisterListener(NewMockListener(name)) + if err != nil { + t.Errorf("DeregsiterListener Error %s", err) + } + } + if len(ls.listeners) != 0 { + t.Errorf("Expected number of listeners to be %d, got %d", 0, len(ls.listeners)) + } +} + +func TestSingleListenerMock(t *testing.T) { + listener1Name := "listener1" + listener1Output := info + listener1Name + " mocked info" + testListenersCalled(t, []string{listener1Name}, []string{listener1Output}) +} + +func TestMultipleListenerMock(t *testing.T) { + listener1Name := "listener1" + listener1Output := info + listener1Name + " mocked info" + listener2Name := "listener2" + listener2Output := info + listener2Name + " mocked info" + testListenersCalled(t, []string{listener1Name, listener2Name}, []string{listener1Output, listener2Output}) +} + +func testListenersCalled(t *testing.T, listenerNames []string, outputs []string) { + for _, name := range listenerNames { + err := RegisterListener(NewMockListener(name)) + if err != nil { + t.Errorf("RegsiterListener Error %s", err) + } + } + var f bytes.Buffer + const ts = "test" + golog.SetOutput(&f) + lg := NewWithPlugin("testplugin") + lg.Info(ts) + for _, str := range outputs { + if x := f.String(); !strings.Contains(x, str) { + t.Errorf("Expected log to contain %s, got %s", str, x) + } + } + for _, name := range listenerNames { + err := DeregisterListener(NewMockListener(name)) + if err != nil { + t.Errorf("DeregsiterListener Error %s", err) + } + } + +} + +type mockListener struct { + name string +} + +func NewMockListener(name string) *mockListener { + return &mockListener{name: name} +} + +func (l *mockListener) Name() string { + return l.name +} + +func (l *mockListener) Debug(plugin string, v ...interface{}) { + log(debug, l.name+" mocked debug") +} + +func (l *mockListener) Debugf(plugin string, format string, v ...interface{}) { + log(debug, l.name+" mocked debug") +} + +func (l *mockListener) Info(plugin string, v ...interface{}) { + log(info, l.name+" mocked info") +} + +func (l *mockListener) Infof(plugin string, format string, v ...interface{}) { + log(info, l.name+" mocked info") +} + +func (l *mockListener) Warning(plugin string, v ...interface{}) { + log(warning, l.name+" mocked warning") +} + +func (l *mockListener) Warningf(plugin string, format string, v ...interface{}) { + log(warning, l.name+" mocked warning") +} + +func (l *mockListener) Error(plugin string, v ...interface{}) { + log(err, l.name+" mocked error") +} + +func (l *mockListener) Errorf(plugin string, format string, v ...interface{}) { + log(err, l.name+" mocked error") +} + +func (l *mockListener) Fatal(plugin string, v ...interface{}) { + log(fatal, l.name+" mocked fatal") +} + +func (l *mockListener) Fatalf(plugin string, format string, v ...interface{}) { + log(fatal, l.name+" mocked fatal") +} diff --git a/plugin/pkg/log/plugin.go b/plugin/pkg/log/plugin.go index 8dbffa07e..1be79f111 100644 --- a/plugin/pkg/log/plugin.go +++ b/plugin/pkg/log/plugin.go @@ -27,6 +27,7 @@ func (p P) Debug(v ...interface{}) { if !D.Value() { return } + ls.debug(p.plugin, v...) p.log(debug, v...) } @@ -35,29 +36,56 @@ func (p P) Debugf(format string, v ...interface{}) { if !D.Value() { return } + ls.debugf(p.plugin, format, v...) p.logf(debug, format, v...) } // Info logs as log.Info. -func (p P) Info(v ...interface{}) { p.log(info, v...) } +func (p P) Info(v ...interface{}) { + ls.info(p.plugin, v...) + p.log(info, v...) +} // Infof logs as log.Infof. -func (p P) Infof(format string, v ...interface{}) { p.logf(info, format, v...) } +func (p P) Infof(format string, v ...interface{}) { + ls.infof(p.plugin, format, v...) + p.logf(info, format, v...) +} // Warning logs as log.Warning. -func (p P) Warning(v ...interface{}) { p.log(warning, v...) } +func (p P) Warning(v ...interface{}) { + ls.warning(p.plugin, v...) + p.log(warning, v...) +} // Warningf logs as log.Warningf. -func (p P) Warningf(format string, v ...interface{}) { p.logf(warning, format, v...) } +func (p P) Warningf(format string, v ...interface{}) { + ls.warningf(p.plugin, format, v...) + p.logf(warning, format, v...) +} // Error logs as log.Error. -func (p P) Error(v ...interface{}) { p.log(err, v...) } +func (p P) Error(v ...interface{}) { + ls.error(p.plugin, v...) + p.log(err, v...) +} // Errorf logs as log.Errorf. -func (p P) Errorf(format string, v ...interface{}) { p.logf(err, format, v...) } +func (p P) Errorf(format string, v ...interface{}) { + ls.errorf(p.plugin, format, v...) + p.logf(err, format, v...) +} // Fatal logs as log.Fatal and calls os.Exit(1). -func (p P) Fatal(v ...interface{}) { p.log(fatal, v...); os.Exit(1) } +func (p P) Fatal(v ...interface{}) { + ls.fatal(p.plugin, v...) + p.log(fatal, v...) + os.Exit(1) +} // Fatalf logs as log.Fatalf and calls os.Exit(1). -func (p P) Fatalf(format string, v ...interface{}) { p.logf(fatal, format, v...); os.Exit(1) } +func (p P) Fatalf(format string, v ...interface{}) { + ls.fatalf(p.plugin, format, v...) + p.logf(fatal, format, v...) + os.Exit(1) +} |