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 <bradfitz@tailscale.com>
Signed-off-by: Andrea Gottardo <andrea@gottardo.me>
This commit is contained in:
Andrea GottardoandBrad Fitzpatrick authored and Brad Fitzpatrick committed 2026-09-29 13:16:16 -07:00
1 parent 7649cf9501
commit 5e21c7cc10
3 files changed
+3 -29

No files matched your search

-1
View File
@@ -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
+2 -25
View File
@@ -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"...)
}
+1 -3
View File
@@ -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