util/eventbus: allow logging of slow subscribers (#17705)
Add options to the eventbus.Bus to plumb in a logger. Route that logger in to the subscriber machinery, and trigger a log message to it when a subscriber fails to respond to its delivered events for 5s or more. The log message includes the package, filename, and line number of the call site that created the subscription. Add tests that verify this works. Updates #17680 Change-Id: I0546516476b1e13e6a9cf79f19db2fe55e56c698 Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
This commit is contained in:
@@ -4,8 +4,11 @@
|
||||
package eventbus_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
@@ -436,6 +439,76 @@ func TestMonitor(t *testing.T) {
|
||||
t.Run("Wait", testMon(t, func(c *eventbus.Client, m eventbus.Monitor) { c.Close(); m.Wait() }))
|
||||
}
|
||||
|
||||
func TestSlowSubs(t *testing.T) {
|
||||
swapLogBuf := func(t *testing.T) *bytes.Buffer {
|
||||
logBuf := new(bytes.Buffer)
|
||||
save := log.Writer()
|
||||
log.SetOutput(logBuf)
|
||||
t.Cleanup(func() { log.SetOutput(save) })
|
||||
return logBuf
|
||||
}
|
||||
|
||||
t.Run("Subscriber", func(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
buf := swapLogBuf(t)
|
||||
|
||||
b := eventbus.New()
|
||||
defer b.Close()
|
||||
|
||||
pc := b.Client("pub")
|
||||
p := eventbus.Publish[EventA](pc)
|
||||
|
||||
sc := b.Client("sub")
|
||||
s := eventbus.Subscribe[EventA](sc)
|
||||
|
||||
go func() {
|
||||
time.Sleep(6 * time.Second) // trigger the slow check at 5s.
|
||||
t.Logf("Subscriber accepted %v", <-s.Events())
|
||||
}()
|
||||
|
||||
p.Publish(EventA{12345})
|
||||
|
||||
time.Sleep(7 * time.Second) // advance time...
|
||||
synctest.Wait() // subscriber is done
|
||||
|
||||
want := regexp.MustCompile(`^.* tailscale.com/util/eventbus_test bus_test.go:\d+: ` +
|
||||
`subscriber for eventbus_test.EventA is slow.*`)
|
||||
if got := buf.String(); !want.MatchString(got) {
|
||||
t.Errorf("Wrong log output\ngot: %q\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("SubscriberFunc", func(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
buf := swapLogBuf(t)
|
||||
|
||||
b := eventbus.New()
|
||||
defer b.Close()
|
||||
|
||||
pc := b.Client("pub")
|
||||
p := eventbus.Publish[EventB](pc)
|
||||
|
||||
sc := b.Client("sub")
|
||||
eventbus.SubscribeFunc[EventB](sc, func(e EventB) {
|
||||
time.Sleep(6 * time.Second) // trigger the slow check at 5s.
|
||||
t.Logf("SubscriberFunc processed %v", e)
|
||||
})
|
||||
|
||||
p.Publish(EventB{67890})
|
||||
|
||||
time.Sleep(7 * time.Second) // advance time...
|
||||
synctest.Wait() // subscriber is done
|
||||
|
||||
want := regexp.MustCompile(`^.* tailscale.com/util/eventbus_test bus_test.go:\d+: ` +
|
||||
`subscriber for eventbus_test.EventB is slow.*`)
|
||||
if got := buf.String(); !want.MatchString(got) {
|
||||
t.Errorf("Wrong log output\ngot: %q\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestRegression(t *testing.T) {
|
||||
bus := eventbus.New()
|
||||
t.Cleanup(bus.Close)
|
||||
|
||||
Reference in New Issue
Block a user