Skip to content

[unified_analytics] Full log rewrite on every event once log is full #2611

Closed

Description

@davidmorgan

Hi Keerti,

While looking at dart format performance with an agent, it suggested
what looks like a nice optimization: when the log is full, a tweak to how
it's handled could save 14ms on every dart command.

Please let me know if that makes sense and if you'd like me to propose a PR.
Or if not--I'll just drop it, this was just a side note to the actual work :)

Thanks :)

Morgan

Agent generated content follows.


LogHandler.save in lib/src/log_handler.dart reads the entire log file on
every event, and once it holds kLogFileLength = 2500 records it rewrites
the whole file:

records = logFile.readAsLinesSync();
final content = '${jsonEncode(data)}\n';
if (records.length < kLogFileLength) {
  logFile.writeAsStringSync(content, mode: FileMode.writeOnlyAppend);
} else {
  records.add(content);
  records = records.skip(records.length - kLogFileLength).toList();
  logFile.writeAsStringSync(records.join('\n'));
}

Any developer machine that has sent 2500 events is permanently in the second
branch. On mine the log is 1,669,466 bytes and exactly 2500 lines, so every
dart command reads and rewrites 1.6 MB.

Measured cost: about 14 ms per dart format invocation, local SSD. Two
independent derivations, released SDK 3.14.0-75.0.dev, 30 interleaved
repetitions each:

Condition Median
normal network, full log 173.4 ms
normal network, empty log 158.7 ms
no network, full log 68.9 ms
no network, empty log 56.0 ms

"Empty log" is a temporary HOME with the same consent state and client id
but a zero-length dart-flutter-telemetry.log.

Trimming in blocks rather than per record would remove it: for example,
append until the file holds 2 × kLogFileLength records, then trim to
kLogFileLength in one rewrite. That amortises the rewrite over 2500 events
and keeps the append path a single small write. Reading the whole file on
every event to count lines could be avoided the same way, by checking
stat.size against a byte threshold instead of counting records.

Activity

  1. added 3 commits that reference this issue on Sep 29, 2026
    656c24e
    2b000e1
    3b36a04
  2. davidmorgan commented on Sep 29, 2026

    @davidmorgan
    ContributorAuthor

    Hi Keerti,

    I went ahead and put up a draft PR: #2613. It's a draft until you've had a chance to say whether the approach looks good to you, please let me know.

    During the investigation the agent discovered that analysis server currently sends some large bursts of events, which means this is actually a bigger improvement for the IDE than the CLI: currently there is a 2.4s hang on the first 30-minute report, at shutdown, and on the next report after an analysis options or pubspec change.

    before after
    Analytics.send, full log, median 16.6 ms 0.27 ms
    analysis server burst, 129 events 2.42 s 95 ms
    trim, once per roughly 3000 events n/a ~37 ms
  3. davidmorgan commented on Sep 30, 2026

    @davidmorgan
    ContributorAuthor

    (Keerti commented on the PR that it looks good, so: sent for review.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions