From 5e21c7cc1089a6aacf73503fef30cba96f35a0a6 Mon Sep 17 00:00:00 2001 From: Andrea Gottardo Date: Tue, 29 Sep 2026 19:55:05 +0000 Subject: [PATCH] logtail: remove LowMemory mode LowMemory shrank the pending ring buffer, upload batch size, and text truncation limit for iOS, back when network extensions were limited to 15 MB. All supported iOS versions now allow 50 MB, so the savings are negligible and the extra code paths are not worth maintaining. Fixes #13685 Change-Id: Ic0c26f899ce00f105399c7b1e687e2b92194687e Co-authored-by: Brad Fitzpatrick Signed-off-by: Andrea Gottardo --- logtail/config.go | 1 - logtail/logtail.go | 27 ++------------------------- logtail/logtail_test.go | 4 +--- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/logtail/config.go b/logtail/config.go index 0ee599905..55e99e445 100644 --- a/logtail/config.go +++ b/logtail/config.go @@ -32,7 +32,6 @@ type Config struct { BaseURL string // if empty defaults to "https://log.tailscale.com" HTTPC *http.Client // if empty defaults to http.DefaultClient SkipClientTime bool // if true, client_time is not written to logs - LowMemory bool // if true, logtail minimizes memory use Clock tstime.Clock // if set, Clock.Now substitutes uses of time.Now Stderr io.Writer // if set, logs are sent here instead of os.Stderr Bus *eventbus.Bus // if set, uses the eventbus for awaitInternetUp instead of callback diff --git a/logtail/logtail.go b/logtail/logtail.go index f8e1d103b..74a572db7 100644 --- a/logtail/logtail.go +++ b/logtail/logtail.go @@ -51,9 +51,6 @@ const maxSize = 256 << 10 // Note that JSON log messages can be as large as maxSize. const maxTextSize = 16 << 10 -// lowMemRatio reduces maxSize and maxTextSize by this ratio in lowMem mode. -const lowMemRatio = 4 - // bufferSize is the typical buffer size to retain. // It is large enough to handle most log messages, // but not too large to be a notable waste of memory if retained forever. @@ -76,11 +73,7 @@ func newLogger(cfg Config) *Logger { cfg.Stderr = os.Stderr } if cfg.Buffer == nil { - pendingSize := 256 - if cfg.LowMemory { - pendingSize = 64 - } - cfg.Buffer = NewMemoryBuffer(pendingSize) + cfg.Buffer = NewMemoryBuffer(256) } var procID uint32 if cfg.IncludeProcID { @@ -113,7 +106,6 @@ func newLogger(cfg Config) *Logger { stderrLevel: int64(cfg.StderrLevel), httpc: cfg.HTTPC, url: cfg.BaseURL + "/c/" + cfg.Collection + "/" + cfg.PrivateID.String() + urlSuffix, - lowMem: cfg.LowMemory, buffer: cfg.Buffer, maxUploadSize: cfg.MaxUploadSize, skipClientTime: cfg.SkipClientTime, @@ -217,9 +209,6 @@ func UploadLogs[T any](ctx context.Context, conf Config, entries iter.Seq[LogEnt lg := newLogger(conf) maxLen := cmp.Or(lg.maxUploadSize, maxSize) - if lg.lowMem { - maxLen /= lowMemRatio - } // body accumulates a JSON array of encoded entries: "[e1,e2,...]". // The framing mirrors Logger.drainPending. @@ -302,7 +291,6 @@ type Logger struct { stderrLevel int64 // accessed atomically httpc *http.Client url string - lowMem bool skipClientTime bool netMonitor *netmon.Monitor buffer Buffer @@ -457,13 +445,6 @@ func (lg *Logger) drainPending() (b []byte) { }() maxLen := cmp.Or(lg.maxUploadSize, maxSize) - if lg.lowMem { - // When operating in a low memory environment, it is better to upload - // in multiple operations than it is to allocate a large body and OOM. - // Even if maxLen is less than maxSize, we can still upload an entry - // that is up to maxSize if we happen to encounter one. - maxLen /= lowMemRatio - } for len(b) < maxLen { line, err := lg.buffer.TryReadLine() switch { @@ -882,12 +863,8 @@ func (lg *Logger) appendText(dst, src []byte, skipClientTime bool, procID uint32 // Append the text string, which may be truncated. // Invalid UTF-8 will be mangled with the Unicode replacement character. - max := maxTextSize - if lg.lowMem { - max /= lowMemRatio - } dst = append(dst, `"text":`...) - dst = appendTruncatedString(dst, src, max) + dst = appendTruncatedString(dst, src, maxTextSize) return append(dst, "}\n"...) } diff --git a/logtail/logtail_test.go b/logtail/logtail_test.go index 0c1b62670..44182880b 100644 --- a/logtail/logtail_test.go +++ b/logtail/logtail_test.go @@ -759,7 +759,6 @@ func TestAppendText(t *testing.T) { var lg Logger lg.clock = tstest.NewClock(tstest.ClockOpts{Start: time.Date(2000, 01, 01, 0, 0, 0, 0, time.UTC)}) lg.metricsDelta = func() string { return "metrics" } - lg.lowMem = true for _, tt := range []struct { text string @@ -774,7 +773,7 @@ func TestAppendText(t *testing.T) { {skipClientTime: true, procID: 1, procSeq: 2, want: `{"logtail":{"proc_id":1,"proc_seq":2},"metrics":"metrics"}`}, {text: "fizz buzz", want: `{"logtail":{"client_time":"2000-01-01T00:00:00Z"},"metrics":"metrics","text":"fizz buzz"}`}, {text: "\b\f\n\r\t\"\\", want: `{"logtail":{"client_time":"2000-01-01T00:00:00Z"},"metrics":"metrics","text":"\b\f\n\r\t\"\\"}`}, - {text: "x" + strings.Repeat("😐", maxSize), want: `{"logtail":{"client_time":"2000-01-01T00:00:00Z"},"metrics":"metrics","text":"x` + strings.Repeat("😐", 1023) + `…+1044484"}`}, + {text: "x" + strings.Repeat("😐", maxSize), want: `{"logtail":{"client_time":"2000-01-01T00:00:00Z"},"metrics":"metrics","text":"x` + strings.Repeat("😐", 4095) + `…+1032196"}`}, } { got := string(lg.appendText(nil, []byte(tt.text), tt.skipClientTime, tt.procID, tt.procSeq, tt.level)) if !strings.HasSuffix(got, "\n") { @@ -794,7 +793,6 @@ func TestAppendTextOrJSON(t *testing.T) { var lg Logger lg.clock = tstest.NewClock(tstest.ClockOpts{Start: time.Date(2000, 01, 01, 0, 0, 0, 0, time.UTC)}) lg.metricsDelta = func() string { return "metrics" } - lg.lowMem = true for _, tt := range []struct { in string