Commit edbe02c0 authored by Shane Xie's avatar Shane Xie Committed by GitHub

core: add log listeners for k8s_event plugin (#5451)

add log listener interface
Signed-off-by: default avatarxh4n3 <xyn1016@gmail.com>
parent 29f3dcfa
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()
}
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() {
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)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment