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

@ -117,12 +117,7 @@ func TestEncodeAndUploadMessages(t *testing.T) {
io.WriteString(l, tt.log) io.WriteString(l, tt.log)
body := <-ts.uploaded body := <-ts.uploaded
data := make(map[string]interface{}) data := unmarshalOne(t, body)
err := json.Unmarshal(body, &data)
if err != nil {
t.Error(err)
}
got := data["text"] got := data["text"]
if got != tt.want { if got != tt.want {
t.Errorf("%s: got %q; want %q", tt.name, got.(string), 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. // JSON log message already contains a logtail field.
io.WriteString(l, `{"logtail": "LOGTAIL", "text": "text"}`) io.WriteString(l, `{"logtail": "LOGTAIL", "text": "text"}`)
body := <-ts.uploaded body := <-ts.uploaded
data := make(map[string]interface{}) data := unmarshalOne(t, body)
err := json.Unmarshal(body, &data)
if err != nil {
t.Error(err)
}
errorHasLogtail, ok := data["error_has_logtail"] errorHasLogtail, ok := data["error_has_logtail"]
if ok { if ok {
if errorHasLogtail != "LOGTAIL" { if errorHasLogtail != "LOGTAIL" {
@ -186,11 +177,7 @@ func TestEncodeSpecialCases(t *testing.T) {
l.skipClientTime = true l.skipClientTime = true
io.WriteString(l, "text") io.WriteString(l, "text")
body = <-ts.uploaded body = <-ts.uploaded
data = make(map[string]interface{}) data = unmarshalOne(t, body)
err = json.Unmarshal(body, &data)
if err != nil {
t.Error(err)
}
_, ok = data["logtail"] _, ok = data["logtail"]
if ok { if ok {
t.Errorf("skipClientTime: unexpected logtail map present: %v", data) t.Errorf("skipClientTime: unexpected logtail map present: %v", data)
@ -204,11 +191,7 @@ func TestEncodeSpecialCases(t *testing.T) {
longStr := strings.Repeat("0", 512) longStr := strings.Repeat("0", 512)
io.WriteString(l, longStr) io.WriteString(l, longStr)
body = <-ts.uploaded body = <-ts.uploaded
data = make(map[string]interface{}) data = unmarshalOne(t, body)
err = json.Unmarshal(body, &data)
if err != nil {
t.Error(err)
}
text, ok := data["text"] text, ok := data["text"]
if !ok { if !ok {
t.Errorf("lowMem: no text %v", data) 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 { if err != nil {
t.Error(err) t.Error(err)
} }
@ -326,3 +309,16 @@ func TestPublicIDUnmarshalText(t *testing.T) {
t.Errorf("allocs = %v; want 0", n) 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