Skip to content

refactor: format log records without allocating - #68

Merged
sbogomolov merged 2 commits into
mainfrom
logger/format-without-allocating
Aug 8, 2026
Merged

refactor: format log records without allocating#68
sbogomolov merged 2 commits into
mainfrom
logger/format-without-allocating

Conversation

@sbogomolov

Copy link
Copy Markdown
Owner

Every emitted record allocated twice — std::format built a string for the message, std::println another for the line. Both now format into stack buffers and go out in one fwrite. Suppressed records were already free (the level gate runs first), so this is about the lines that do emit, which at Info includes per-packet paths.

Two details worth a look:

  • Separate message buffer. With a single buffer an over-long message would eat the (file:line) suffix — losing the source location exactly when it is most wanted. Splitting them means the message loses its own tail instead, and it is marked [...] rather than cut silently.
  • The record buffer holds back its last slot for the newline, so a truncated record still ends its line and the whole thing is still one write. ASan confirms the reservation is load-bearing: dropping the - 1 yields a stack-buffer-overflow, caught by the new record-truncation test.

Scope: this does not make logging allocation-free. IpAddress::ToString and MacAddress::ToString still allocate inside their formatters (a MAC is 17 chars, past SSO, so every time). Removing those needs a non-allocating conversion on the types themselves — tracked as follow-up.

Also carries the signed/unsigned comparison convention this review settled, as its own commit.

Native (891) and docker/Linux (878) green.

Every emitted record allocated twice: std::format built a string for
the message and std::println another for the line. Both now format
into stack buffers, written out in one fwrite.

The message gets its own buffer so an over-long one loses its own tail
rather than the source location after it, and is marked [...] rather
than cut silently. The record buffer holds back its last slot for the
newline, which keeps a truncated record on one line.

Formatters that go through ToString (IpAddress, MacAddress) still
allocate; removing that needs a non-allocating conversion on those
types.
@sbogomolov sbogomolov self-assigned this Aug 8, 2026
@sbogomolov
sbogomolov merged commit b7ec008 into main Aug 8, 2026
17 checks passed
@sbogomolov
sbogomolov deleted the logger/format-without-allocating branch August 8, 2026 22:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant