Skip to content

Skip redundant setBreadcrumbs observer call on the addBreadcrumb path #5686

Description

@runningcode

Problem

Scope.addBreadcrumb notifies every scope observer twice per breadcrumb:

for (final IScopeObserver observer : options.getScopeObservers()) {
  observer.addBreadcrumb(breadcrumb);
  observer.setBreadcrumbs(breadcrumbs);   // <-- redundant right after an add
}

For PersistingScopeObserver, setBreadcrumbs is a guaranteed no-op right after an add — it only does work when the collection is empty (the clear case), and its own comment says so. But it still acquires the SynchronizedQueue lock via isEmpty() and iterates the whole observer list a second time on every breadcrumb.

Evidence

From on-device method trace analysis (median.perfetto-trace): breadcrumb adds go through the observer loop on every call. Removing the second per-observer notification halves the observer iteration + drops a redundant lock acquisition per breadcrumb.

⚠️ Risk — public API contract

IScopeObserver is a public interface. A third-party observer could implement only setBreadcrumbs (relying on it being called on every add) rather than the incremental addBreadcrumb. Removing the call changes the observer notification contract on the add path.

Options to de-risk:

  • Keep both notifications but document the redundancy, OR
  • Remove the setBreadcrumbs call on the add path and treat as an intentional, documented contract clarification (observers must implement addBreadcrumb for incremental updates).

Needs a maintainer decision on the contract before merging. Draft PR removes the call with this caveat flagged.

Fix (proposed)

for (final IScopeObserver observer : options.getScopeObservers()) {
  observer.addBreadcrumb(breadcrumb);
}

Acceptance

Observer notified once per breadcrumb add; clearBreadcrumbs still calls setBreadcrumbs; API-contract decision recorded on the PR.

Metadata

Metadata

Assignees

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions