From ed2950bffeebeb48260ee53d4f4822b5b5e1d07e Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Wed, 24 Sep 2025 06:19:46 +0200 Subject: [PATCH 01/18] rfc(feature): Logs for Crashes --- README.md | 1 + text/0148-logs-for-crashes.md | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 text/0148-logs-for-crashes.md diff --git a/README.md b/README.md index 1a5677dc..ed5cfdda 100644 --- a/README.md +++ b/README.md @@ -69,3 +69,4 @@ This repository contains RFCs and DACIs. Lost? - [0143-sdk-fail-safe-mode](text/0143-sdk-fail-safe-mode.md): SDK Fail-Safe Mode - [0141-linking-traces](text/0141-linking-traces.md): Support Linking Traces - [0146-automatic-in-app-rules](text/0146-automatic-in-app-rules.md): For Java projects, when a code mapping is automatically created, also create an in-app stack trace rules to categorize the frames as in-app +- [0148-logs-for-crashes](text/0148-logs-for-crashes.md): Logs for Crashes diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md new file mode 100644 index 00000000..abb15a42 --- /dev/null +++ b/text/0148-logs-for-crashes.md @@ -0,0 +1,35 @@ +- Start Date: 2025-09-24 +- RFC Type: feature +- RFC PR: https://github.com/getsentry/rfcs/pull/148 +- RFC Status: draft + +# Summary + +One paragraph explanation of the feature or document purpose. + +# Motivation + +Why are we doing this? What use cases does it support? What is the expected outcome? + +# Background + +The reason this decision or document is required. This section might not always exist. + +# Supporting Data + +[Metrics to help support your decision (if applicable).] + +# Options Considered + +If an RFC does not know yet what the options are, it can propose multiple options. The +preferred model is to propose one option and to provide alternatives. + +# Drawbacks + +Why should we not do this? What are the drawbacks of this RFC or a particular option if +multiple options are presented. + +# Unresolved questions + +- What parts of the design do you expect to resolve through this RFC? +- What issues are out of scope for this RFC but are known? From bd5ca6f86d9fe39eee665586940fcd6f53b05c9b Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Wed, 24 Sep 2025 06:43:24 +0200 Subject: [PATCH 02/18] first version --- text/0148-logs-for-crashes.md | 189 +++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 5 deletions(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index abb15a42..d3e42d4b 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -2,28 +2,172 @@ - RFC Type: feature - RFC PR: https://github.com/getsentry/rfcs/pull/148 - RFC Status: draft +- - RFC Author: @philipphofmann # Summary -One paragraph explanation of the feature or document purpose. +This RFC aims to develop a strategy for SDKs to prevent the loss of logs when an application terminates abnormally, such as a crash or watchdog termination. # Motivation -Why are we doing this? What use cases does it support? What is the expected outcome? +Understanding the sequence of events leading up to an abnormal termination is crucial for diagnosing and resolving the underlying issue. Users currently rely on breadcrumbs to reconstruct this timeline. Since we want logs to serve as the primary debugging tool and eventual replacement for breadcrumbs, users must be able to rely on logs reaching Sentry reliably, even when the application terminates abnormally. # Background -The reason this decision or document is required. This section might not always exist. +The Cocoa and Java SDKs implement scope observers that continuously synchronize scope data to their respective crash handling backends (SentryCrash for Cocoa, sentry-native for Java). This stores scope information in C memory, making it accessible during signal handlers when crashes occur. For watchdog terminations, both SDKs persist scope data directly to disk since the crash handling backends cannot capture these terminations. The Cocoa SDK performs disk writes synchronously on the calling thread, while the Java SDK uses a dedicated background thread due to Android's strict mode restrictions on main thread disk I/O. Both implementations use persistent file handles to minimize I/O overhead, with thread safety guaranteed by the scope's existing synchronization mechanisms. -# Supporting Data +Links to implementations: -[Metrics to help support your decision (if applicable).] +* Java [PersistingScopeObserver](https://github.com/getsentry/sentry-java/blob/main/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java) +* [SentryCrashScopeObserver](https://github.com/getsentry/sentry-cocoa/blob/d8ceea3a0ce99c0dd499d3b9472c87aaf0713d3c/Sources/Sentry/SentryCrashScopeObserver.m) +* [SentryWatchdogTerminationScopeObserver](https://github.com/getsentry/sentry-cocoa/blob/main/Sources/Sentry/SentryWatchdogTerminationScopeObserver.m) + +## Requirements + +1. The solution MUST NOT lose any log messages in the event of a crash. + +```swift +logger.trace("Starting database connection") + +// The above log must show up in Sentry +SentrySDK.crash() +``` +2. The solution should minimize the loss of log messages for watchdog terminations. +3. The solution MUST NOT block the main thread. +4. The solution MUST be thread-safe. +5. The solution MUST work for hybrid SDKs. +6. The solution SHOULD NOT depend on or interfere with the offline caching of envelopes, meaning once we tackle the cache overflow problem with priority queues or whatever, little or no changes SHOULD be required for this solution. +7. The solution MAY also work for spans and other future telemetry data. # Options Considered If an RFC does not know yet what the options are, it can propose multiple options. The preferred model is to propose one option and to provide alternatives. +## A - FIFO Queue With Async IO + +The https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/ stores its logs in a thread-safe FIFO queue, living in a crash-safe memory space. When the BatchProcessor receives a log, it performs the following steps + +1. Put the log into the FIFO queue on the calling thread. +2. On a background thread, serialize the next log of the FIFO queue and store it in the `BatchProcessorCacheFile`. +3. Remove the log from the FIFO queue. +4. If the queue isn’t empty, go to step 2. + +When a crash occurs, the SDKs write the logs in the FIFO queue to the `LogCrashRecoveryFile` and send these logs on the next SDK launch. + +If a crash occurs during step 2 and before step 3, we must ensure that we do not send a log twice. Currently, logs don’t have IDs, so we can’t deduplicate them when looking at the `BatchProcessorCacheFile` and `LogCrashRecoveryFile`. Therefore, SDKs MUST add an extra ID to the serialized logs, which the SDKs MUST NOT send to Sentry, so they can deduplicate logs after a crash has occurred. + +For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. + +This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `BatchProcessorCacheFile` and send these. + +The BatchProcessors MUST keep `BatchProcessorCacheFiles` . When it sends the logs of logs`logs-cache-file1` it must store new logs to `logs-cache-file2` until the SDK stores the envelope successfully, to avoid losing logs if a crash occurs in between. These are the flushing steps: + +1. Reroute new logs to `logs-cache-file2` +2. Load logs into memory and store them in an envelope. +3. Delete all logs from `logs-cache-file1` + +We intentionally ignore the edge case of the application crashing directly between storing the envelope and deleting `logs-cache-file1` , because the SDK overreports logs but doesn’t lose them. Currently, no SDKs cover these edge case for other data, such as crashes. We can follow up on this, if we see it’s a problem for users. Then we can apply strategies from databases by using log or marker files to ensure, the SDK doesn’t duplicate logs in that edge case. + +The BatchProcessor maintains its logic of batching multiple logs together into a single envelope to avoid multiple HTTP requests. + +Hybrid SDKs pass every span down to the native SDKs, which will put every log in their BatchProcessor and it’s cache. + +### Pros + +1. Not blocking the main thread. +2. Only native mobile SDKs need to implement this approach, and hybrid SDKs don’t. + +### Cons + +1. Not a 100% guarantee to drop any logs for watchdog terminations. +2. A slight synchronization overhead is required for storing logs in the crash-safe data structure. +3. The solution adds a slight serialization overhead when passing logs layers, such as React-Native to Java, or Swift/Objective-C to C. +4. Potential duplication of logs in a few crash scenarios. + + +## ~~B - Store Logs on Calling Thread~~ + +> **⛔ Dismissed because it blocks the main thread, and on Android, that’s a red flag because of strict mode.** + + +The logs implementation already has the https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/, which minimizes the number of HTTP requests SDKs make to the backend for logs. Currently, the BatchProcessor keeps the serialized logs in memory and flushes them out in batches. + +With this option, the BatchProcessor stores the serialized logs on the calling thread to disk. The DiskBatchProcessor keeps the timeout logic to ensure the delay of sending logs to Sentry is minimal. + +For efficiency, the BatchProcessor MUST use file handles or file streams when writing logs to disk. For thread safety, the BatchProcessor uses a single file for the main thread, eliminating the need for synchronization. All other threads share one other file with synchronization. We accept the overhead of synchronization for all other threads, because it’s acceptable to block non-main threads slightly. Furthermore, we don’t want to keep one file handle per thread, because some operating systems have a limit on the number of open file handles, and each file handle consumes resources. + +When the BatchProcessor flushes either because the timeout expires or the logs exceed a yet-to-be-defined size limit, the BatchProcessor starts new files for both the main thread and other threads, and only deletes the old files once the logs are stored as an envelope to disk to ensure logs don’t get lost when a crash occurs. + +When the DiskBatchProcessor initializes, it checks if there are logs from a previous launch stored and flushes them. + +When the user closes the SDK, the BatchProcessor flushes the logs stored on disk. + +### File IO Overhead on an iPhone 12 + +This test used transactions to measure the overhead of the existing storing of breadcrumbs to disk via an [NSFileHandle on the Cocoa SDK](https://github.com/getsentry/sentry-cocoa/blob/8cf2d438359420b985edc968081d5df3ca037a9a/Sources/Sentry/Processors/SentryWatchdogTerminationBreadcrumbProcessor.m#L40-L49). The test was conducted using the iOS-Swift app, with a local release build that excluded the debugger. + +```objectivec +- (void)addSerializedBreadcrumb:(NSDictionary *)crumb +{ + SENTRY_LOG_DEBUG(@"Adding breadcrumb: %@", crumb); + + id transaction = [SentrySDKInternal startTransactionWithName:@"StoreCrumbToDisk" operation:@"crumb"]; + + id serializeCrumbSpan = [transaction startChildWithOperation:@"serialize" description:@"StoreCrumbToDisk.serialize"]; + NSData *_Nullable jsonData = [SentrySerialization dataWithJSONObject:crumb]; + [serializeCrumbSpan finish]; + + id spanOverhead = [transaction startChildWithOperation:@"serialize" description:@"StoreCrumbToDisk.spanOverhead"]; + [spanOverhead finish]; + + if (jsonData == nil) { + SENTRY_LOG_ERROR(@"Error serializing breadcrumb to JSON"); + return; + } + + id storeCrumbSpan = [transaction startChildWithOperation:@"file.io" description:@"StoreCrumbToDisk.store"]; + [self storeBreadcrumb:SENTRY_UNWRAP_NULLABLE(NSData, jsonData)]; + [storeCrumbSpan finish]; + + [transaction finish]; +} +``` + +![Screenshot 2025-09-16 at 12.30.28.png](attachment:3c0c845c-d3a6-4f62-b78e-6dc633daf4e1:Screenshot_2025-09-16_at_12.30.28.png) + +The result shows that storing breadcrumbs to disk takes less than 0.1ms on average. What’s weird, though, is that the serialized span appears to be faster than the span overhead span, which is basically a span started and finished immediately. + +Nevertheless, this overhead is small and may be acceptable for the assurance that no logs are lost. It’s worth investigating the overhead for storing logs to disk on different iPhones and Android devices. + +### Pros + +1. The SDKs always send logs for crashes and watchdog terminations. + +### Cons + +1. It adds slight IO overhead on the main thread for every single log. +2. On [Android](https://developer.android.com/reference/android/os/StrictMode), this will trigger strict mode warnings, which is a know out criteria. + + +## ~~C - Store Logs Async~~ + +> ⛔ **Dismissed because of con 1 and requirement 1.** + + +Similar to [~~A - Store Logs on Calling Thread~~ ](https://www.notion.so/A-Store-Logs-on-Calling-Thread-26a8b10e4b5d803b9bc1fba4deba15f5?pvs=21) the BatchProcessor, but it always stores logs to disk on a background thread. The most significant advantage over a solely in-memory BatchProcessor is that when a crash or watchdog termination occurs, almost all logs are recovered. + + +### Pros + +1. The SDKs don’t block the main thread. +2. The SDKs can recover almost all logs in the event of a crash or watchdog termination. +3. Easy to implement. + +### Cons + +1. When a crash or watchdog termination occurs, some logs may be missing. On Cocoa, users rely on breadcrumbs for investigating watchdog terminations. If some logs are missing, users may be reluctant to migrate from breadcrumbs to logs. + # Drawbacks Why should we not do this? What are the drawbacks of this RFC or a particular option if @@ -33,3 +177,38 @@ multiple options are presented. - What parts of the design do you expect to resolve through this RFC? - What issues are out of scope for this RFC but are known? + +## ~~D - CrashReporter Sync~~ + +> ⛔ **Dismissed because of con 1.** ⛔ + +The mobile SDKs already sync scope data and breadcrumbs across multiple layers into C memory for SentryCrash and sentry-native. When the crash reporter generates a crash report, it includes this data from the C memory in the report. This solution does the same for logs. When a crash occurs, the SDKs store the logs in C memory and save them to a file. On the next launch, they recover the logs. + +We must use C memory because, in specific edge cases, we can’t access Objective-C or Java memory due to asynchronous safety concerns. Doing so can break other signal handlers, which is undesirable. We already broke this principle to make transactions and SR for crashes work, which works most of the time, but not for all types of crashes. + +### Pros + +1. The SDK doesn’t block the main thread with file IO operations. +2. The SDK sends logs for crashes. + +### Cons + +1. The SDKs lose numerous logs for watchdog terminations. + +## ~~E - OnCrash Hook~~ + +> ⛔ **Dismissed because of con 1.** ⛔ + + +Similar to how we already make transactions and SR work for crashes, we could add a hook that tries to serialize the in-memory logs in Java / Swift to disk when a crash occurs. This works for most of the crashes, but not all. + +### Pros + +1. Easy to implement. +2. No extra overhead for the main thread. + +### Cons + +1. The SDKs lose numerous logs for watchdog terminations. +2. Doesn’t work for all types of crashes. +3. We violate async safety for signal handlers, but we already do that for transactions and SR for crashes. From eaeba55f1b6eccc3f1385ca42b3e9c7cde378594 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Wed, 24 Sep 2025 08:21:46 +0200 Subject: [PATCH 03/18] improve --- ...s-for-crashes-ios-crumb-overhead-spans.png | Bin 0 -> 116296 bytes text/0148-logs-for-crashes.md | 43 +++++++++++------- 2 files changed, 26 insertions(+), 17 deletions(-) create mode 100644 text/0148-logs-for-crashes-ios-crumb-overhead-spans.png diff --git a/text/0148-logs-for-crashes-ios-crumb-overhead-spans.png b/text/0148-logs-for-crashes-ios-crumb-overhead-spans.png new file mode 100644 index 0000000000000000000000000000000000000000..fc18dafab22a63d423c213609f2d57a4071d176e GIT binary patch literal 116296 zcmeFZWn5KV*Dp+iC?zT-umR~(y1P4+?%H(crcp$?n+?*Ubcd95cgIGFO>es6Y_I!% zj?ep?`||R9eh(k`t+nS|bImd4e~vNch!v`$B#nhhjER7NfF&yog=&*0YO06)6v+}#@rQPVh*&j7o>zW zwNe7C%mgVlITc?jI*OZHTFHQ%&DB9luT4QVro3j9!a|q=o_z2D?95$_0iJfY_AY#$ zf|P%a%Ll*y`7&RV4DZ40;$`n@?8$8JLiKZqe~lqw?qcd} z<>+eVU=R2?rm=~Go2wutCA=N*@4;QIEPjn{@A7Z*;f!GY*~0pYc}!NL0Kuc7{G)Ba7{uckNlR`B_<{q@+-7x1ZAd79g5 zOIX>N+q?WVEGG}g|7g|vZ>?;vICy?Fzi}~l7I(0NKMNmJ-PG9}K8U4*D<$hsp0oa& z>G0KK{ol(6zxm$)Ft>-Vx-)!vo4KeJ5D+lyti;7tWW~h+D$WiTR<`B{2r{9G$>=KT z+5|l??=6aKY6%g!O-0Z{0QI|PjjrW*aR`C9CYYG+W=^OxL17pSjExLAM!6qIRhgKA z!t@Eu@KmR}g0K={h~l$L4lS^B*x;gvpUZN?z4t!Y12~KvU^|Ex9$e0VpiP5Iyp&2Q3&%SLStjIo( zdVz%yhyS<`>NtT*s`lucJ7uQGJ4eKC2HM(l0`GM3xTKvsF`{?a)$VfQ&$x%41k;4X z7p(L(D-bR#1D-zQZMcUz-8c+9?k}8vDUL?3|M*F;C+XUv-^d`gYB?RXfJqqY*U*~> zO3CP5O0P8g<5fV@X_*uTg;CF`hPkOzGi^L^ zc`?D+%WnGg&{aq`J1dzCU$~1msNPZ1E_IAzf|p5Bk1|?qH<%Uk1Z==9;)Ja|-ny&b zrZJe9--ALw9LTOOY}lDGoj^lpy?S_iQ|Myy^wK1?%!Ik(rCRI=0UE=P@eIo@J)$Eg zrIElWF$B<3e^M2k%99N20tljVZnd7V-xXRF%MIqsUTi&$W=zSC9k(a1PMh0Z5$z66FYvqI|tbkIM;} zkiUph(4nQbaj9T4v>Q0$K1b{krQ$(m31VD9+eBGf!P`W$ zhMX<17=Zo((M$ABh3*L|wOF4D@r$6fQ8r7g*N+lK)AYQ!qijft~+C}~?s{`^4XGQwKXB7M(eu|(rs

lkI(SZ9&kUn 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Ľjcd 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 C1Z&j* literal 0 HcmV?d00001 diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index d3e42d4b..828ecf1f 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -4,6 +4,7 @@ - RFC Status: draft - - RFC Author: @philipphofmann + # Summary This RFC aims to develop a strategy for SDKs to prevent the loss of logs when an application terminates abnormally, such as a crash or watchdog termination. @@ -41,38 +42,36 @@ SentrySDK.crash() # Options Considered -If an RFC does not know yet what the options are, it can propose multiple options. The -preferred model is to propose one option and to provide alternatives. - ## A - FIFO Queue With Async IO -The https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/ stores its logs in a thread-safe FIFO queue, living in a crash-safe memory space. When the BatchProcessor receives a log, it performs the following steps +The [BatchProcessor](https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/) stores its logs in a thread-safe FIFO queue, living in a crash-safe memory space. When the BatchProcessor receives a log, it performs the following steps 1. Put the log into the FIFO queue on the calling thread. 2. On a background thread, serialize the next log of the FIFO queue and store it in the `BatchProcessorCacheFile`. 3. Remove the log from the FIFO queue. -4. If the queue isn’t empty, go to step 2. - -When a crash occurs, the SDKs write the logs in the FIFO queue to the `LogCrashRecoveryFile` and send these logs on the next SDK launch. - -If a crash occurs during step 2 and before step 3, we must ensure that we do not send a log twice. Currently, logs don’t have IDs, so we can’t deduplicate them when looking at the `BatchProcessorCacheFile` and `LogCrashRecoveryFile`. Therefore, SDKs MUST add an extra ID to the serialized logs, which the SDKs MUST NOT send to Sentry, so they can deduplicate logs after a crash has occurred. +4. If the queue isn’t empty, go to step 2. -For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. +When a crash occurs, the SDKs write the logs in the FIFO queue to the `LogCrashRecoveryFile` and send these logs on the next SDK launch. For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `BatchProcessorCacheFile` and send these. -This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `BatchProcessorCacheFile` and send these. - -The BatchProcessors MUST keep `BatchProcessorCacheFiles` . When it sends the logs of logs`logs-cache-file1` it must store new logs to `logs-cache-file2` until the SDK stores the envelope successfully, to avoid losing logs if a crash occurs in between. These are the flushing steps: +The BatchProcessor MUST keep two `BatchProcessorCacheFiles`. When it sends the logs from `logs-cache-file1`, it must store new logs to `logs-cache-file2` until the SDK stores the envelope successfully, to avoid losing logs if a crash occurs in between. These are the flushing steps: 1. Reroute new logs to `logs-cache-file2` 2. Load logs into memory and store them in an envelope. 3. Delete all logs from `logs-cache-file1` -We intentionally ignore the edge case of the application crashing directly between storing the envelope and deleting `logs-cache-file1` , because the SDK overreports logs but doesn’t lose them. Currently, no SDKs cover these edge case for other data, such as crashes. We can follow up on this, if we see it’s a problem for users. Then we can apply strategies from databases by using log or marker files to ensure, the SDK doesn’t duplicate logs in that edge case. - -The BatchProcessor maintains its logic of batching multiple logs together into a single envelope to avoid multiple HTTP requests. +The BatchProcessor maintains its logic of batching multiple logs together into a single envelope to avoid multiple HTTP requests. Hybrid SDKs pass every span down to the native SDKs, which will put every log in their BatchProcessor and it’s cache. +### Duplicated Logs Edge Cases + +We intentionally ignore duplicate logs in two edge cases: + +1) if the application crashes between storing the envelope and deleting `logs-cache-file1`. +2) if a crash occurs during step 2 and before step 3, where logs might exist in both the `BatchProcessorCacheFile` and `LogCrashRecoveryFile`. + +In both cases, the SDK will send duplicate logs on the next launch. While this isn't acceptable long-term, we accept it for now because solving this correctly is complicated and we don't currently handle this edge case for other telemetry data such as crashes. If duplicate logs become problematic, we can implement database-style atomic operations using marker files or something similar to prevent duplication. + ### Pros 1. Not blocking the main thread. @@ -134,7 +133,7 @@ This test used transactions to measure the overhead of the existing storing of b } ``` -![Screenshot 2025-09-16 at 12.30.28.png](attachment:3c0c845c-d3a6-4f62-b78e-6dc633daf4e1:Screenshot_2025-09-16_at_12.30.28.png) +![Screenshot 2025-09-16 at 12.30.28.png](./0148-logs-for-crashes-ios-crumb-overhead-spans.png) The result shows that storing breadcrumbs to disk takes less than 0.1ms on average. What’s weird, though, is that the serialized span appears to be faster than the span overhead span, which is basically a span started and finished immediately. @@ -212,3 +211,13 @@ Similar to how we already make transactions and SR work for crashes, we could ad 1. The SDKs lose numerous logs for watchdog terminations. 2. Doesn’t work for all types of crashes. 3. We violate async safety for signal handlers, but we already do that for transactions and SR for crashes. + + + +# Useful resources + +On Cocoa, we can get inspired by [CacheAdvance](https://github.com/dfed/CacheAdvance), which is an open source lib storing anything implementing Swift Codable to disk using file handles. The solution isn’t thread-safe. + +# Unresolved Questions + +1. Is it acceptable to have duplicated logs in certain edge cases, as pointed out in [Option A](#a---fifo-queue-with-async-io). From cb24277abd5209f462ec4d0eace68f6349638292 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Wed, 24 Sep 2025 08:22:31 +0200 Subject: [PATCH 04/18] remove duplicated unresolved questions --- text/0148-logs-for-crashes.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index 828ecf1f..01c9110b 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -167,16 +167,6 @@ Similar to [~~A - Store Logs on Calling Thread~~ ](https://www.notion.so/A-Store 1. When a crash or watchdog termination occurs, some logs may be missing. On Cocoa, users rely on breadcrumbs for investigating watchdog terminations. If some logs are missing, users may be reluctant to migrate from breadcrumbs to logs. -# Drawbacks - -Why should we not do this? What are the drawbacks of this RFC or a particular option if -multiple options are presented. - -# Unresolved questions - -- What parts of the design do you expect to resolve through this RFC? -- What issues are out of scope for this RFC but are known? - ## ~~D - CrashReporter Sync~~ > ⛔ **Dismissed because of con 1.** ⛔ @@ -218,6 +208,11 @@ Similar to how we already make transactions and SR work for crashes, we could ad On Cocoa, we can get inspired by [CacheAdvance](https://github.com/dfed/CacheAdvance), which is an open source lib storing anything implementing Swift Codable to disk using file handles. The solution isn’t thread-safe. +# Drawbacks + +Why should we not do this? What are the drawbacks of this RFC or a particular option if +multiple options are presented. + # Unresolved Questions 1. Is it acceptable to have duplicated logs in certain edge cases, as pointed out in [Option A](#a---fifo-queue-with-async-io). From 1c0781ab25a86f12a0f8814ce1818ba1963251b9 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Wed, 24 Sep 2025 08:22:53 +0200 Subject: [PATCH 05/18] another fix --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index 01c9110b..d7eaee5a 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -2,7 +2,7 @@ - RFC Type: feature - RFC PR: https://github.com/getsentry/rfcs/pull/148 - RFC Status: draft -- - RFC Author: @philipphofmann +- RFC Author: @philipphofmann # Summary From 4265be6133874eeeb0d8fa5206fa39b8b65d5e7a Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Thu, 25 Sep 2025 08:23:41 +0200 Subject: [PATCH 06/18] wording improvements --- text/0148-logs-for-crashes.md | 38 ++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index d7eaee5a..dad2015f 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -4,7 +4,6 @@ - RFC Status: draft - RFC Author: @philipphofmann - # Summary This RFC aims to develop a strategy for SDKs to prevent the loss of logs when an application terminates abnormally, such as a crash or watchdog termination. @@ -15,13 +14,15 @@ Understanding the sequence of events leading up to an abnormal termination is cr # Background -The Cocoa and Java SDKs implement scope observers that continuously synchronize scope data to their respective crash handling backends (SentryCrash for Cocoa, sentry-native for Java). This stores scope information in C memory, making it accessible during signal handlers when crashes occur. For watchdog terminations, both SDKs persist scope data directly to disk since the crash handling backends cannot capture these terminations. The Cocoa SDK performs disk writes synchronously on the calling thread, while the Java SDK uses a dedicated background thread due to Android's strict mode restrictions on main thread disk I/O. Both implementations use persistent file handles to minimize I/O overhead, with thread safety guaranteed by the scope's existing synchronization mechanisms. +The Cocoa and Java SDKs implement scope observers that continuously synchronize scope data to their respective crash handling backends (SentryCrash for Cocoa, sentry-native for Java). The scope observers store the information in C memory, so when a crash occurs, the crash handlers can access that information [async safe](https://man7.org/linux/man-pages/man7/signal-safety.7.html) and write it to disk. +For watchdog terminations, both SDKs persist scope data directly to disk since the crash handling backends cannot capture these terminations. The Cocoa SDK performs disk writes synchronously on the calling thread, while the Java SDK uses a dedicated background thread due to Android's strict mode restrictions on main thread disk I/O. Both implementations use file handles to minimize I/O overhead, with thread safety guaranteed by the scope's existing synchronization mechanisms. -Links to implementations: +Links to some implementations: -* Java [PersistingScopeObserver](https://github.com/getsentry/sentry-java/blob/main/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java) -* [SentryCrashScopeObserver](https://github.com/getsentry/sentry-cocoa/blob/d8ceea3a0ce99c0dd499d3b9472c87aaf0713d3c/Sources/Sentry/SentryCrashScopeObserver.m) -* [SentryWatchdogTerminationScopeObserver](https://github.com/getsentry/sentry-cocoa/blob/main/Sources/Sentry/SentryWatchdogTerminationScopeObserver.m) +* Java: [PersistingScopeObserver](https://github.com/getsentry/sentry-java/blob/main/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java) +* Java: [NdkScopeObserver](https://github.com/getsentry/sentry-java/blob/d21770841d84eddba0636e2082c029db2a158457/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java) +* Cocoa: [SentryCrashScopeObserver](https://github.com/getsentry/sentry-cocoa/blob/d8ceea3a0ce99c0dd499d3b9472c87aaf0713d3c/Sources/Sentry/SentryCrashScopeObserver.m) +* Cocoa: [SentryWatchdogTerminationScopeObserver](https://github.com/getsentry/sentry-cocoa/blob/main/Sources/Sentry/SentryWatchdogTerminationScopeObserver.m) ## Requirements @@ -33,7 +34,8 @@ logger.trace("Starting database connection") // The above log must show up in Sentry SentrySDK.crash() ``` -2. The solution should minimize the loss of log messages for watchdog terminations. + +2. The solution SHOULD minimize the loss of log messages for watchdog terminations. 3. The solution MUST NOT block the main thread. 4. The solution MUST be thread-safe. 5. The solution MUST work for hybrid SDKs. @@ -44,31 +46,35 @@ SentrySDK.crash() ## A - FIFO Queue With Async IO -The [BatchProcessor](https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/) stores its logs in a thread-safe FIFO queue, living in a crash-safe memory space. When the BatchProcessor receives a log, it performs the following steps +The existing [BatchProcessor](https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/) minimizes the number of HTTP requests that SDKs make to Sentry for logs and currently stores the logs in memory. When a crash happens, all these logs are lost. + +With this option, the BatchProcessor stores its logs in a thread-safe FIFO queue, residing in an async-safe memory space, allowing the crash reporter to write them to disk when a crash occurs. Furthermore, the BatchProcessor stores logs asynchronously into a file, allowing it to recover after an abnormal termination, for which the crash handler can't run. + +When the BatchProcessor receives a log, it performs the following steps 1. Put the log into the FIFO queue on the calling thread. -2. On a background thread, serialize the next log of the FIFO queue and store it in the `BatchProcessorCacheFile`. +2. On a background thread, serialize the next log of the FIFO queue and store it in the `batch-processor-cache-file`. 3. Remove the log from the FIFO queue. 4. If the queue isn’t empty, go to step 2. -When a crash occurs, the SDKs write the logs in the FIFO queue to the `LogCrashRecoveryFile` and send these logs on the next SDK launch. For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `BatchProcessorCacheFile` and send these. +When a crash occurs, the SDKs write the logs in the FIFO queue to the `log-crash-recover-file` and send these logs on the next SDK launch. For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `batch-processor-cache-file` and send these. -The BatchProcessor MUST keep two `BatchProcessorCacheFiles`. When it sends the logs from `logs-cache-file1`, it must store new logs to `logs-cache-file2` until the SDK stores the envelope successfully, to avoid losing logs if a crash occurs in between. These are the flushing steps: +The BatchProcessor MUST keep two `BatchProcessorCacheFiles`. When it sends the logs from `batch-processor-cache-file-1`, it must store new logs to `batch-processor-cache-file-2` until the SDK stores the envelope successfully, to avoid losing logs if a crash occurs in between. These are the flushing steps: -1. Reroute new logs to `logs-cache-file2` +1. Reroute new logs to `batch-processor-cache-file-2` 2. Load logs into memory and store them in an envelope. -3. Delete all logs from `logs-cache-file1` +3. Delete all logs from `batch-processor-cache-file-1` The BatchProcessor maintains its logic of batching multiple logs together into a single envelope to avoid multiple HTTP requests. -Hybrid SDKs pass every span down to the native SDKs, which will put every log in their BatchProcessor and it’s cache. +Hybrid SDKs pass every span down to the native SDKs, which will put every log in their BatchProcessor and its cache. ### Duplicated Logs Edge Cases We intentionally ignore duplicate logs in two edge cases: -1) if the application crashes between storing the envelope and deleting `logs-cache-file1`. -2) if a crash occurs during step 2 and before step 3, where logs might exist in both the `BatchProcessorCacheFile` and `LogCrashRecoveryFile`. +1) if the application crashes between storing the envelope and deleting a `batch-processor-cache-file` or `log-crash-recover-file`. +2) if a crash occurs between step 2 and before step 3 of the FIFO queue process, where logs might exist in both the `batch-processor-cache-file` and the FIFO queue. In both cases, the SDK will send duplicate logs on the next launch. While this isn't acceptable long-term, we accept it for now because solving this correctly is complicated and we don't currently handle this edge case for other telemetry data such as crashes. If duplicate logs become problematic, we can implement database-style atomic operations using marker files or something similar to prevent duplication. From 451e384c5e7e23cb7e6499b18605ed8c31c45c13 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Fri, 26 Sep 2025 14:53:15 +0200 Subject: [PATCH 07/18] feedback from Abhi --- text/0148-logs-for-crashes.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index dad2015f..4023d146 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -57,6 +57,8 @@ When the BatchProcessor receives a log, it performs the following steps 3. Remove the log from the FIFO queue. 4. If the queue isn’t empty, go to step 2. +The FIFO queue has a `max-logs-count` of 64 logs. When logs the FIFO exceeds `max-logs-count`, the BatchProcessor MUST drop logs and record client reports with the category `queue_overflow` for every dropped log. SDKs MAY choose a different `max-logs-count` value, if needed. + When a crash occurs, the SDKs write the logs in the FIFO queue to the `log-crash-recover-file` and send these logs on the next SDK launch. For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `batch-processor-cache-file` and send these. The BatchProcessor MUST keep two `BatchProcessorCacheFiles`. When it sends the logs from `batch-processor-cache-file-1`, it must store new logs to `batch-processor-cache-file-2` until the SDK stores the envelope successfully, to avoid losing logs if a crash occurs in between. These are the flushing steps: @@ -85,7 +87,7 @@ In both cases, the SDK will send duplicate logs on the next launch. While this i ### Cons -1. Not a 100% guarantee to drop any logs for watchdog terminations. +1. Not a 100% guarantee to drop any logs for watchdog terminations, because when a watchdog termination occurs the SDK looses all logs in the FIFO queue. 2. A slight synchronization overhead is required for storing logs in the crash-safe data structure. 3. The solution adds a slight serialization overhead when passing logs layers, such as React-Native to Java, or Swift/Objective-C to C. 4. Potential duplication of logs in a few crash scenarios. From 6730db9c4959cb50d78ca23bb49417e07d2bb801 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Tue, 30 Sep 2025 06:41:05 +0200 Subject: [PATCH 08/18] explain no timeout fifo queue --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index 4023d146..eddfbe73 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -48,7 +48,7 @@ SentrySDK.crash() The existing [BatchProcessor](https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/) minimizes the number of HTTP requests that SDKs make to Sentry for logs and currently stores the logs in memory. When a crash happens, all these logs are lost. -With this option, the BatchProcessor stores its logs in a thread-safe FIFO queue, residing in an async-safe memory space, allowing the crash reporter to write them to disk when a crash occurs. Furthermore, the BatchProcessor stores logs asynchronously into a file, allowing it to recover after an abnormal termination, for which the crash handler can't run. +With this option, the BatchProcessor stores its logs in a thread-safe FIFO queue, residing in an async-safe memory space, allowing the crash reporter to write them to disk when a crash occurs. Furthermore, the BatchProcessor stores logs asynchronously into a file, allowing it to recover after an abnormal termination, for which the crash handler can't run. The BatchProcessor MUST store the logs immidiately to disk after adding them to the FIFO queue. It MUST NOT use a timeout as it does for flushing the logs to Sentry to minimize data loss in case of a watchdog termination. When the BatchProcessor receives a log, it performs the following steps From 1d818593dcecf464accfc495d683c595224f0229 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Tue, 30 Sep 2025 09:43:50 +0200 Subject: [PATCH 09/18] include feedback --- text/0148-logs-for-crashes.md | 40 ++++++++++++++++------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index eddfbe73..fa51f79b 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -35,12 +35,12 @@ logger.trace("Starting database connection") SentrySDK.crash() ``` -2. The solution SHOULD minimize the loss of log messages for watchdog terminations. -3. The solution MUST NOT block the main thread. -4. The solution MUST be thread-safe. -5. The solution MUST work for hybrid SDKs. -6. The solution SHOULD NOT depend on or interfere with the offline caching of envelopes, meaning once we tackle the cache overflow problem with priority queues or whatever, little or no changes SHOULD be required for this solution. -7. The solution MAY also work for spans and other future telemetry data. +1. The solution SHOULD minimize the loss of log messages for watchdog terminations. This MAY vary based on the platform. If the platforms allows it, SDKs SHOULD try to not loose any logs for watchdog terminations. +2. The solution MUST NOT block the main thread. +3. The solution MUST be thread-safe. +4. The solution MUST work for hybrid SDKs. +5. The solution SHOULD NOT depend on or interfere with the offline caching of envelopes, meaning once we tackle the cache overflow problem with priority queues or whatever, little or no changes SHOULD be required for this solution. +6. The solution MAY also work for spans and other future telemetry data. # Options Considered @@ -57,29 +57,26 @@ When the BatchProcessor receives a log, it performs the following steps 3. Remove the log from the FIFO queue. 4. If the queue isn’t empty, go to step 2. -The FIFO queue has a `max-logs-count` of 64 logs. When logs the FIFO exceeds `max-logs-count`, the BatchProcessor MUST drop logs and record client reports with the category `queue_overflow` for every dropped log. SDKs MAY choose a different `max-logs-count` value, if needed. +The FIFO queue has a `max-logs-count` of 64 logs. When the FIFO queue exceeds `max-logs-count` log items, the BatchProcessor MUST drop logs and record client reports with the category `queue_overflow` for every dropped log. SDKs MAY choose a different `max-logs-count` value, if needed. -When a crash occurs, the SDKs write the logs in the FIFO queue to the `log-crash-recover-file` and send these logs on the next SDK launch. For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `batch-processor-cache-file` and send these. +When a crash occurs, the SDKs write the logs in the FIFO queue to the `log-crash-recover-file` and send these logs on the next SDK launch. To avoid sending duplicated logs, the SDKs MUST deduplicate the logs from the `log-crash-recover-file` and `batch-processor-cache-file` based on the logID after a crash before sending them. It's worth noting that logs don't have an ID yet, and we MUST extend the protocol for this. -The BatchProcessor MUST keep two `BatchProcessorCacheFiles`. When it sends the logs from `batch-processor-cache-file-1`, it must store new logs to `batch-processor-cache-file-2` until the SDK stores the envelope successfully, to avoid losing logs if a crash occurs in between. These are the flushing steps: +For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `batch-processor-cache-file` and send these. -1. Reroute new logs to `batch-processor-cache-file-2` -2. Load logs into memory and store them in an envelope. -3. Delete all logs from `batch-processor-cache-file-1` +The BatchProcessor MUST keep two `batch-processor-cache-files`. When it sends the logs from `batch-processor-cache-file`, it renames it to `batch-processor-cache-file-to-flush` and creates a new `batch-processor-cache-file` to avoid losing logs if a crash occurs when flushing the logs. To avoid sending duplicate logs if the app crashes in between storing the envelope and deleting the cache file, the BatchProcessor MUST first store the envelope to the same folder as the BatchProcessor file. After deleting the `batch-processor-cache-file-to-flush`, SDKs MUST move the envelope to the envelope cache folder. As moving files can be done atomic, SDKs avoid sending duplicated logs in the described scenario. We're going to add a more detailed explanation once we add this concept to the develop docs. These are the flushing steps: + +1. Rename `batch-processor-cache-file` to `batch-processor-cache-file-to-flush`. +2. Create a new `batch-processor-cache-file` +3. Store new logs to `batch-processor-cache-file` +4. Load logs into memory from the `batch-processor-cache-file-to-flush` +5. Store the logs in memory into an envelope into the batch processor directory, which MUST be the same folder as the other BatchProcessor files, and name it `batch-processor-cache-envelope-to-flush`. +6. Delete all logs from `batch-processor-cache-file-to-flush` +7. Move the `batch-processor-cache-envelope-to-flush` to the envelopes cache folder. The BatchProcessor maintains its logic of batching multiple logs together into a single envelope to avoid multiple HTTP requests. Hybrid SDKs pass every span down to the native SDKs, which will put every log in their BatchProcessor and its cache. -### Duplicated Logs Edge Cases - -We intentionally ignore duplicate logs in two edge cases: - -1) if the application crashes between storing the envelope and deleting a `batch-processor-cache-file` or `log-crash-recover-file`. -2) if a crash occurs between step 2 and before step 3 of the FIFO queue process, where logs might exist in both the `batch-processor-cache-file` and the FIFO queue. - -In both cases, the SDK will send duplicate logs on the next launch. While this isn't acceptable long-term, we accept it for now because solving this correctly is complicated and we don't currently handle this edge case for other telemetry data such as crashes. If duplicate logs become problematic, we can implement database-style atomic operations using marker files or something similar to prevent duplication. - ### Pros 1. Not blocking the main thread. @@ -90,7 +87,6 @@ In both cases, the SDK will send duplicate logs on the next launch. While this i 1. Not a 100% guarantee to drop any logs for watchdog terminations, because when a watchdog termination occurs the SDK looses all logs in the FIFO queue. 2. A slight synchronization overhead is required for storing logs in the crash-safe data structure. 3. The solution adds a slight serialization overhead when passing logs layers, such as React-Native to Java, or Swift/Objective-C to C. -4. Potential duplication of logs in a few crash scenarios. ## ~~B - Store Logs on Calling Thread~~ From 57d096c6f9f5aa61c1d2f8a12554e7af16cdb811 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Tue, 30 Sep 2025 09:45:17 +0200 Subject: [PATCH 10/18] typo --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index fa51f79b..44412d25 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -63,7 +63,7 @@ When a crash occurs, the SDKs write the logs in the FIFO queue to the `log-crash For the Cocoa SDK, the crash-safe memory space structure MUST be C memory, because Swift and Objective-C aren’t async-safe. For Java, it’s Java memory, because the JVM allows you to store logs in memory or on disk when a crash occurs. This solution also works for watchdog terminations, as the BatchProcessor MUST check on SDK launch if there are logs in the `batch-processor-cache-file` and send these. -The BatchProcessor MUST keep two `batch-processor-cache-files`. When it sends the logs from `batch-processor-cache-file`, it renames it to `batch-processor-cache-file-to-flush` and creates a new `batch-processor-cache-file` to avoid losing logs if a crash occurs when flushing the logs. To avoid sending duplicate logs if the app crashes in between storing the envelope and deleting the cache file, the BatchProcessor MUST first store the envelope to the same folder as the BatchProcessor file. After deleting the `batch-processor-cache-file-to-flush`, SDKs MUST move the envelope to the envelope cache folder. As moving files can be done atomic, SDKs avoid sending duplicated logs in the described scenario. We're going to add a more detailed explanation once we add this concept to the develop docs. These are the flushing steps: +The BatchProcessor MUST keep two `batch-processor-cache-files`. When it sends the logs from `batch-processor-cache-file`, it renames it to `batch-processor-cache-file-to-flush` and creates a new `batch-processor-cache-file` to avoid losing logs if a crash occurs when flushing the logs. To avoid sending duplicate logs if the app crashes in between storing the envelope and deleting the cache file, the BatchProcessor MUST first store the envelope to the same folder as the BatchProcessor files. After deleting the `batch-processor-cache-file-to-flush`, SDKs MUST move the envelope to the envelope cache folder. As moving files can be done atomic, SDKs avoid sending duplicated logs in the described scenario. We're going to add a more detailed explanation once we add this concept to the develop docs. These are the flushing steps: 1. Rename `batch-processor-cache-file` to `batch-processor-cache-file-to-flush`. 2. Create a new `batch-processor-cache-file` From bced8a7088d9885e51715181345c5bc6b49b88eb Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Thu, 2 Oct 2025 09:26:14 +0200 Subject: [PATCH 11/18] update wording for hybrid --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index 44412d25..3a5ad201 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -75,7 +75,7 @@ The BatchProcessor MUST keep two `batch-processor-cache-files`. When it sends th The BatchProcessor maintains its logic of batching multiple logs together into a single envelope to avoid multiple HTTP requests. -Hybrid SDKs pass every span down to the native SDKs, which will put every log in their BatchProcessor and its cache. +Hybrid SDKs pass every span down to the native SDKs, which will put every log in their BatchProcessor and its cache when logs are ready for sending, meaning after they go through beforeLog, integrations, processors, etc. ### Pros From 4a4b13a17017d4668c9783cef00066d5ba99c54d Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Thu, 2 Oct 2025 09:28:42 +0200 Subject: [PATCH 12/18] add author and approver --- text/0148-logs-for-crashes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index 3a5ad201..4ce0aa86 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -1,8 +1,9 @@ - Start Date: 2025-09-24 - RFC Type: feature - RFC PR: https://github.com/getsentry/rfcs/pull/148 -- RFC Status: draft +- RFC Status: In Progress - RFC Author: @philipphofmann +- RFC Approver: # Summary From ebdac44f29b72028546ca27b14278eaac6ee7b94 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Thu, 2 Oct 2025 09:33:40 +0200 Subject: [PATCH 13/18] add decision and abhi as approver --- text/0148-logs-for-crashes.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index 4ce0aa86..c3d8132e 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -3,12 +3,16 @@ - RFC PR: https://github.com/getsentry/rfcs/pull/148 - RFC Status: In Progress - RFC Author: @philipphofmann -- RFC Approver: +- RFC Approver: @AbhiPrasad # Summary This RFC aims to develop a strategy for SDKs to prevent the loss of logs when an application terminates abnormally, such as a crash or watchdog termination. +# Decision + +We decided to go with [Option A - FIFO Queue With Async IO](#a---fifo-queue-with-async-io), because the other options all had some knockout criteria. This option is the basis for adding a more detailed spec to the BatchProcessor in the [develop docs](https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/). + # Motivation Understanding the sequence of events leading up to an abnormal termination is crucial for diagnosing and resolving the underlying issue. Users currently rely on breadcrumbs to reconstruct this timeline. Since we want logs to serve as the primary debugging tool and eventual replacement for breadcrumbs, users must be able to rely on logs reaching Sentry reliably, even when the application terminates abnormally. @@ -208,16 +212,7 @@ Similar to how we already make transactions and SR work for crashes, we could ad 3. We violate async safety for signal handlers, but we already do that for transactions and SR for crashes. - # Useful resources On Cocoa, we can get inspired by [CacheAdvance](https://github.com/dfed/CacheAdvance), which is an open source lib storing anything implementing Swift Codable to disk using file handles. The solution isn’t thread-safe. -# Drawbacks - -Why should we not do this? What are the drawbacks of this RFC or a particular option if -multiple options are presented. - -# Unresolved Questions - -1. Is it acceptable to have duplicated logs in certain edge cases, as pointed out in [Option A](#a---fifo-queue-with-async-io). From 6f2d49b803216c2d7bff925e431df21f152db65d Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Fri, 3 Oct 2025 06:10:03 +0200 Subject: [PATCH 14/18] Update text/0148-logs-for-crashes.md Co-authored-by: Abhijeet Prasad --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index c3d8132e..ee5911ed 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -53,7 +53,7 @@ SentrySDK.crash() The existing [BatchProcessor](https://develop.sentry.dev/sdk/telemetry/spans/batch-processor/) minimizes the number of HTTP requests that SDKs make to Sentry for logs and currently stores the logs in memory. When a crash happens, all these logs are lost. -With this option, the BatchProcessor stores its logs in a thread-safe FIFO queue, residing in an async-safe memory space, allowing the crash reporter to write them to disk when a crash occurs. Furthermore, the BatchProcessor stores logs asynchronously into a file, allowing it to recover after an abnormal termination, for which the crash handler can't run. The BatchProcessor MUST store the logs immidiately to disk after adding them to the FIFO queue. It MUST NOT use a timeout as it does for flushing the logs to Sentry to minimize data loss in case of a watchdog termination. +With this option, the BatchProcessor stores its logs in a thread-safe FIFO queue, residing in an async-safe memory space, allowing the crash reporter to write them to disk when a crash occurs. Furthermore, the BatchProcessor stores logs asynchronously into a file, allowing it to recover after an abnormal termination, for which the crash handler can't run. The BatchProcessor MUST store the logs immediately to disk after adding them to the FIFO queue. It MUST NOT use a timeout as it does for flushing the logs to Sentry to minimize data loss in case of a watchdog termination. When the BatchProcessor receives a log, it performs the following steps From 37e77e11fad1de5645cfa759b6cb56995461b15c Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Fri, 3 Oct 2025 06:10:13 +0200 Subject: [PATCH 15/18] Update text/0148-logs-for-crashes.md Co-authored-by: Abhijeet Prasad --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index ee5911ed..fb7187e0 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -89,7 +89,7 @@ Hybrid SDKs pass every span down to the native SDKs, which will put every log in ### Cons -1. Not a 100% guarantee to drop any logs for watchdog terminations, because when a watchdog termination occurs the SDK looses all logs in the FIFO queue. +1. Not a 100% guarantee to drop any logs for watchdog terminations, because when a watchdog termination occurs the SDK loses all logs in the FIFO queue. 2. A slight synchronization overhead is required for storing logs in the crash-safe data structure. 3. The solution adds a slight serialization overhead when passing logs layers, such as React-Native to Java, or Swift/Objective-C to C. From 106bb9518d92ebfef7dcb4d8effb5c001aa66c82 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Fri, 3 Oct 2025 06:10:43 +0200 Subject: [PATCH 16/18] Update text/0148-logs-for-crashes.md Co-authored-by: Roman Zavarnitsyn --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index fb7187e0..2d4641ab 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -80,7 +80,7 @@ The BatchProcessor MUST keep two `batch-processor-cache-files`. When it sends th The BatchProcessor maintains its logic of batching multiple logs together into a single envelope to avoid multiple HTTP requests. -Hybrid SDKs pass every span down to the native SDKs, which will put every log in their BatchProcessor and its cache when logs are ready for sending, meaning after they go through beforeLog, integrations, processors, etc. +Hybrid SDKs pass every log down to the native SDKs, which will put every log in their BatchProcessor and its cache when logs are ready for sending, meaning after they go through beforeLog, integrations, processors, etc. ### Pros From e8a376b45fc64fcea0c89d39a309e2565d4b5d16 Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Fri, 3 Oct 2025 06:19:33 +0200 Subject: [PATCH 17/18] feedback abhi --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index 2d4641ab..86990a95 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -75,7 +75,7 @@ The BatchProcessor MUST keep two `batch-processor-cache-files`. When it sends th 3. Store new logs to `batch-processor-cache-file` 4. Load logs into memory from the `batch-processor-cache-file-to-flush` 5. Store the logs in memory into an envelope into the batch processor directory, which MUST be the same folder as the other BatchProcessor files, and name it `batch-processor-cache-envelope-to-flush`. -6. Delete all logs from `batch-processor-cache-file-to-flush` +6. Delete the file `batch-processor-cache-file-to-flush` 7. Move the `batch-processor-cache-envelope-to-flush` to the envelopes cache folder. The BatchProcessor maintains its logic of batching multiple logs together into a single envelope to avoid multiple HTTP requests. From e01c07d51d2c44aa86e6c9988f053755734bb26e Mon Sep 17 00:00:00 2001 From: Philipp Hofmann Date: Fri, 3 Oct 2025 15:40:44 +0200 Subject: [PATCH 18/18] mark as done --- text/0148-logs-for-crashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0148-logs-for-crashes.md b/text/0148-logs-for-crashes.md index 86990a95..77c077ee 100644 --- a/text/0148-logs-for-crashes.md +++ b/text/0148-logs-for-crashes.md @@ -1,7 +1,7 @@ - Start Date: 2025-09-24 - RFC Type: feature - RFC PR: https://github.com/getsentry/rfcs/pull/148 -- RFC Status: In Progress +- RFC Status: Done - RFC Author: @philipphofmann - RFC Approver: @AbhiPrasad