mirror of
https://github.com/coredns/coredns.git
synced 2025-11-01 18:53:43 -04:00
core: add log listeners for k8s_event plugin (#5451)
add log listener interface Signed-off-by: xh4n3 <xyn1016@gmail.com>
This commit is contained in:
142
plugin/pkg/log/listener.go
Normal file
142
plugin/pkg/log/listener.go
Normal file
@@ -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()
|
||||||
|
}
|
||||||
121
plugin/pkg/log/listener_test.go
Normal file
121
plugin/pkg/log/listener_test.go
Normal file
@@ -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")
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ func (p P) Debug(v ...interface{}) {
|
|||||||
if !D.Value() {
|
if !D.Value() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ls.debug(p.plugin, v...)
|
||||||
p.log(debug, v...)
|
p.log(debug, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,29 +36,56 @@ func (p P) Debugf(format string, v ...interface{}) {
|
|||||||
if !D.Value() {
|
if !D.Value() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ls.debugf(p.plugin, format, v...)
|
||||||
p.logf(debug, format, v...)
|
p.logf(debug, format, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info logs as log.Info.
|
// 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.
|
// 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.
|
// 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.
|
// 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.
|
// 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.
|
// 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).
|
// 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).
|
// 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)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user