logtail: always send a json array

The code goes to some effort to send a single JSON object
when there's only a single line and a JSON array when there
are multiple lines.

It makes the code more complex and more expensive;
when we add a second line, we have to use a second buffer
to duplicate the first one after adding a leading square brackets.

The savings come to two bytes. Instead, always send an array.

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
pull/2677/head
Josh Bleecher Snyder 3 years ago committed by Josh Bleecher Snyder
parent 93284209bc
commit 278e7de9c9

@ -203,6 +203,7 @@ func (l *Logger) drainBlock() (shuttingDown bool) {
// If no logs are available, drainPending blocks until logs are available.
func (l *Logger) drainPending() (res []byte) {
buf := new(bytes.Buffer)
buf.WriteByte('[')
entries := 0
var batchDone bool
@ -242,28 +243,15 @@ func (l *Logger) drainPending() (res []byte) {
b = l.encodeText(b, true)
}
switch {
case entries == 0:
buf.Write(b)
case entries == 1:
buf2 := new(bytes.Buffer)
buf2.WriteByte('[')
buf2.Write(buf.Bytes())
buf2.WriteByte(',')
buf2.Write(b)
buf.Reset()
buf.Write(buf2.Bytes())
default:
if entries > 0 {
buf.WriteByte(',')
buf.Write(b)
}
buf.Write(b)
entries++
}
if entries > 1 {
buf.WriteByte(']')
}
if buf.Len() == 0 {
if buf.Len() <= len("[]") {
return nil
}
return buf.Bytes()

@ -117,12 +117,7 @@ func TestEncodeAndUploadMessages(t *testing.T) {
io.WriteString(l, tt.log)
body := <-ts.uploaded
data := make(map[string]interface{})
err := json.Unmarshal(body, &data)
if err != nil {
t.Error(err)
}
data := unmarshalOne(t, body)
got := data["text"]
if got != tt.want {
t.Errorf("%s: got %q; want %q", tt.name, got.(string), tt.want)
@ -154,11 +149,7 @@ func TestEncodeSpecialCases(t *testing.T) {
// JSON log message already contains a logtail field.
io.WriteString(l, `{"logtail": "LOGTAIL", "text": "text"}`)
body := <-ts.uploaded
data := make(map[string]interface{})
err := json.Unmarshal(body, &data)
if err != nil {
t.Error(err)
}
data := unmarshalOne(t, body)
errorHasLogtail, ok := data["error_has_logtail"]
if ok {
if errorHasLogtail != "LOGTAIL" {
@ -186,11 +177,7 @@ func TestEncodeSpecialCases(t *testing.T) {
l.skipClientTime = true
io.WriteString(l, "text")
body = <-ts.uploaded
data = make(map[string]interface{})
err = json.Unmarshal(body, &data)
if err != nil {
t.Error(err)
}
data = unmarshalOne(t, body)
_, ok = data["logtail"]
if ok {
t.Errorf("skipClientTime: unexpected logtail map present: %v", data)
@ -204,11 +191,7 @@ func TestEncodeSpecialCases(t *testing.T) {
longStr := strings.Repeat("0", 512)
io.WriteString(l, longStr)
body = <-ts.uploaded
data = make(map[string]interface{})
err = json.Unmarshal(body, &data)
if err != nil {
t.Error(err)
}
data = unmarshalOne(t, body)
text, ok := data["text"]
if !ok {
t.Errorf("lowMem: no text %v", data)
@ -219,7 +202,7 @@ func TestEncodeSpecialCases(t *testing.T) {
// -------------------------------------------------------------------------
err = l.Shutdown(context.Background())
err := l.Shutdown(context.Background())
if err != nil {
t.Error(err)
}
@ -326,3 +309,16 @@ func TestPublicIDUnmarshalText(t *testing.T) {
t.Errorf("allocs = %v; want 0", n)
}
}
func unmarshalOne(t *testing.T, body []byte) map[string]interface{} {
t.Helper()
var entries []map[string]interface{}
err := json.Unmarshal(body, &entries)
if err != nil {
t.Error(err)
}
if len(entries) != 1 {
t.Fatalf("expected one entry, got %d", len(entries))
}
return entries[0]
}

Loading…
Cancel
Save