[pull] main from getsentry:main - #411
Merged
Merged
Conversation
Bumps the github-actions group with 2 updates: [getsentry/craft/.github/workflows/changelog-preview.yml](https://github.com/getsentry/craft) and [getsentry/craft](https://github.com/getsentry/craft). Updates `getsentry/craft/.github/workflows/changelog-preview.yml` from 2.27.0 to 2.27.2 - [Release notes](https://github.com/getsentry/craft/releases) - [Changelog](https://github.com/getsentry/craft/blob/master/CHANGELOG.md) - [Commits](getsentry/craft@667b5f5...8fd703e) Updates `getsentry/craft` from 2.27.0 to 2.27.2 - [Release notes](https://github.com/getsentry/craft/releases) - [Changelog](https://github.com/getsentry/craft/blob/master/CHANGELOG.md) - [Commits](getsentry/craft@667b5f5...8fd703e) --- updated-dependencies: - dependency-name: getsentry/craft/.github/workflows/changelog-preview.yml dependency-version: 2.27.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: getsentry/craft dependency-version: 2.27.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* ref(android): Remove unused lock from SentryPerformanceProvider The field was added in #3715 to guard onAppStartDone(), its only user. That method was removed in the 8.x.x merge (#4033), leaving the lock orphaned — it has been allocated on every cold start since, in ContentProvider.onCreate, without ever being acquired. The ISentryLifecycleToken import stays: it is still used for AppStartMetrics.staticLock in shutdown(). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changelog --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
#5867) * perf(android): Parse app start profiling config without JsonSerializer (JAVA-621) SentryPerformanceProvider.launchAppStartProfiler ran in ContentProvider.onCreate — main thread, before Application.onCreate, on every cold start — and built a full JsonSerializer(SentryOptions.empty()) to read one small config file. That path only ever reads options.getLogger(), but JsonSerializer's constructor registers every known deserializer to use exactly one of them. Calling the deserializer directly cuts the parse from 221 to 33 allocations and ~7.5us to ~3.7us (Pixel 10, androidx Microbenchmark, allocationCount is deterministic). Malformed input still yields null so callers keep reporting it as a deserialization failure rather than a read error. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changelog * ref(android): Catch only expected exceptions when parsing profiling config Narrow the deserialization catch from Throwable to Exception. The vendored JSON reader signals bad input with IOException (MalformedJsonException, EOFException), IllegalStateException on token type mismatch, and NumberFormatException on an unparseable number — all Exception subclasses. Catching Throwable additionally swallowed Error, which is never a recoverable "config file is bad" signal. This also restores parity with JsonSerializer.deserialize, which catches Exception, so the replaced behaviour is matched exactly rather than widened. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ref(android): Trim javadoc on deserializeProfilingConfig Drop the paragraph enumerating which exception types the vendored JSON reader throws. That catch (Exception) does not swallow Error is a language-level given, and listing the reader's internal exception types invites the comment to drift as that code changes. The rationale a reader cannot infer from the code — why the deserializer is called directly, and why null is returned instead of rethrowing — stays. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(clientreport): Stop deserializing discarded logs (JAVA-662) ClientReportRecorder counted discarded log and metric items by fully deserializing the envelope payload just to read its size. On the discard path this runs continuously under sustained rate limiting, and the JSON reader's error-tolerant recovery throws an exception per token, pinning CPU cores in a busy-loop (fillInStackTrace dominated the profile). The item count is already stored in the envelope item header, so read it from there instead of deserializing. Byte counts still come from the raw data. This makes the discard path O(1) and allocation/exception-free. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * changelog * test(clientreport): Cover both onDiscard restore entry points (JAVA-662) The two tests asserting that restoring counts from an attached client report does not re-fire onDiscard were named for their setup rather than for what actually differed between them, which made the pair read as an accidental duplicate. Name each for its entry point and share the setup and verifications, so it is clear the property is being pinned for both recordLostEnvelope and recordLostEnvelopeItem. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* perf(core): Batch and coalesce scope-persistence disk writes (JAVA-628) Scope persistence wrote to disk on every scope mutation, which dominated SDK cost during startup: each breadcrumb triggered a synchronous fsync'd QueueFile append, and every other scope field (contexts, trace, user, tags, ...) rewrote its whole file on each change even though only the latest value matters. Coalesce mutations instead of writing eagerly. Each field keeps only its latest pending value and is flushed once per debounce window; breadcrumbs are buffered and appended together behind a single fsync (QueueFile gains an opt-in buffered-write mode plus sync()). This trades a small data-loss window (~100ms before the process dies) for far fewer writes and fsyncs. Persistence exists to enrich crash/ANR events on the next launch, and was already asynchronous, so the widened loss window is acceptable. * Add changelog entry for #5791 * perf(core): Coalesce scope writes on submit instead of a timer (JAVA-628) Scope-persistence flushes were debounced 100ms behind a scheduled task. The debounce was unnecessary: the Sentry executor is single-threaded, so a submitted flush task already sits in the queue long enough for mutations arriving behind it to be folded into the same write. That is exactly the window that matters, since the queue is deepest during startup. Submit the flush instead of scheduling it. Coalescing now tracks executor load rather than a fixed delay, which closes the data-loss window the debounce introduced. Guard against the executor rejecting the task without throwing once its queue is full, which would otherwise leave the pending flag set and stop scope persistence for the rest of the process. Also record why resetCache() deliberately leaves pending mutations alone: they only ever hold values from the current process, so dropping them would lose scope state set during init rather than clearing the previous run's data. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(core): Keep breadcrumbs added during a scope flush (JAVA-628) Batching split one ordered stream of breadcrumb operations into two independent pieces of state: a queue of pending adds and a separate clear flag. Independent state cannot preserve an ordering that the old FIFO executor queue gave for free. flushPending consumed the clear flag with a CAS at the top, then spent the rest of the method serializing and writing each breadcrumb. A clear plus a subsequent add landing in that window had its clear applied after the new breadcrumb was already on disk, so the follow-up flush wiped a breadcrumb that was added after the clear. Breadcrumbs are added from arbitrary threads while the flush runs on the executor thread, so this needs no unusual timing. Enqueue the clear into the breadcrumb queue as a sentinel instead, mirroring the DELETE_MARKER pattern already used for pendingWrites. Ordering becomes intrinsic to the queue rather than something the flush has to reconstruct. This also stops setBreadcrumbs(emptyList()) from calling clear() on the shared queue, which could discard a breadcrumb offered concurrently by another thread even with no flush in flight. * docs(core): Clarify scope-persistence comments (JAVA-628) "Durable" overstated what the buffered-write mode guarantees. sync() issues an fsync, but durability also depends on the storage stack, so describe what the code does — write to disk — rather than promise an outcome it cannot ensure on its own. Also name the pendingBreadcrumbs queue for what it holds: requests to add and clear, not breadcrumbs already buffered. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor(core): Fold the scope flush into one method (JAVA-628) flushPending existed only so the @testonly flush() could do the disk write without the latch bookkeeping that belongs to the queued task. Nothing in production called flush(), and its only test asserted the behaviour of flush() itself, so the second entry point was buying two near-identical methods and a way to corrupt hasPendingFlush. Drop flush() and merge the pair: flush() is now the queued task and writePending() the write it performs. Clear hasPendingFlush in a finally so an unexpected throw cannot leave the flag set, which would stop scope persistence for the rest of the process. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(core): Drop redundant buffered-write QueueFile test (JAVA-628) bufferedWritesSurviveReopenAfterSync was testAddOneElement with a second element and a sync() call: same write, close, reopen, read-it-back shape, and testAddAndRemoveElements already covers round-tripping far more thoroughly. The sync() it appeared to exercise was not actually load-bearing. close() flushes through to the OS whichever mode the file was opened in, so the assertions would hold even if sync() did nothing — the name promised durability semantics the test could not verify in-process. Verifying that would take a killed process, not a reopen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(core): Record that the vendored Tape fork has diverged (JAVA-628) Square archived Tape on 2024-10-25, so the upstream link in each file header points at a snapshot that will never receive fixes. Our copy has also drifted from it: corruption recovery, a bounded ring size, and optional buffered writes. Say both things where a reader will look — the file headers, the class javadoc, and THIRD_PARTY_NOTICES.md — so nobody diffs against upstream expecting it to explain our behaviour, or files a bug there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor(core): Iterate pendingWrites directly when flushing (JAVA-628) writePending() copied the key set into an ArrayList before draining it, which allocates on every flush for no benefit: ConcurrentHashMap's iterator is weakly consistent, so walking it while removing entries is already safe. Removal still goes through the map, not the iterator, because that is an atomic get-and-remove — we never drop a value stored by a mutation racing with the loop. Keys added after iteration starts can be missed, which is fine since flush() re-checks and queues another write. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s on API 35+ (#5841) * fix(android): Drop inflated app start for background-spawned processes on API 35+ When the OS spawns the process for background work (FCM push, job, service, broadcast, etc.) and the user opens the app later, the app start stayed anchored at background process creation, inflating the reported cold start by the whole idle gap. On API 35+ we now use ApplicationStartInfo.getReason() to detect background process starts and mark them as not launched in foreground, so the first created activity re-classifies them as a warm start anchored at activity creation. * docs: fix changelog PR link * docs: trim code comments * docs: trim changelog entry * Update Changelog * Reverse isBackgroundStartReason to isForegroundStartReason * Add extra test --------- Co-authored-by: Markus Hintersteiner <markus.hintersteiner@sentry.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )