wgengine/wglog: improve wireguard-go logging rate limiting

Prior to wireguard-go using printf-style logging,
all wireguard-go logging occurred using format string "%s".
We fixed that but continued to use %s when we rewrote
peer identifiers into Tailscale style.

This commit removes that %sl, which makes rate limiting work correctly.
As a happy side-benefit, it should generate less garbage.

Instead of replacing all wireguard-go peer identifiers
that might occur anywhere in a fully formatted log string,
assume that they only come from args.
Check all args for things that look like *device.Peers
and replace them with appropriately reformatted strings.

There is a variety of ways that this could go wrong
(unusual format verbs or modifiers, peer identifiers
occurring as part of a larger printed object, future API changes),
but none of them occur now, are likely to be added,
or would be hard to work around if they did.

Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
Josh Bleecher Snyder
2021-04-27 10:03:13 -07:00
parent 1f94d43b50
commit 59026a291d
2 changed files with 54 additions and 34 deletions

View File

@@ -15,22 +15,27 @@ import (
func TestLogger(t *testing.T) {
tests := []struct {
in string
want string
omit bool
format string
args []interface{}
want string
omit bool
}{
{"hi", "hi", false},
{"Routine: starting", "", true},
{"peer(IMTB…r7lM) says it misses you", "[IMTBr] says it misses you", false},
{"hi", nil, "hi", false},
{"Routine: starting", nil, "", true},
{"%v says it misses you", []interface{}{stringer("peer(IMTB…r7lM)")}, "[IMTBr] says it misses you", false},
}
c := make(chan string, 1)
type log struct {
format string
args []interface{}
}
c := make(chan log, 1)
logf := func(format string, args ...interface{}) {
s := fmt.Sprintf(format, args...)
select {
case c <- s:
case c <- log{format, args}:
default:
t.Errorf("wrote %q, but shouldn't have", s)
t.Errorf("wrote %q, but shouldn't have", fmt.Sprintf(format, args...))
}
}
@@ -45,15 +50,23 @@ func TestLogger(t *testing.T) {
if tt.omit {
// Write a message ourselves into the channel.
// Then if logf also attempts to write into the channel, it'll fail.
c <- ""
c <- log{}
}
x.DeviceLogger.Errorf(tt.in)
got := <-c
x.DeviceLogger.Errorf(tt.format, tt.args...)
gotLog := <-c
if tt.omit {
continue
}
if got != tt.want {
t.Errorf("Println(%q) = %q want %q", tt.in, got, tt.want)
if got := fmt.Sprintf(gotLog.format, gotLog.args...); got != tt.want {
t.Errorf("Printf(%q, %v) = %q want %q", tt.format, tt.args, got, tt.want)
}
}
}
func stringer(s string) stringerString {
return stringerString(s)
}
type stringerString string
func (s stringerString) String() string { return string(s) }