Skip to content

Commit

Permalink
Feat: Crashed last run (#685)
Browse files Browse the repository at this point in the history
  • Loading branch information
vaind authored Mar 9, 2022
1 parent 15a1229 commit 9eecb1b
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
**Features**:

- Removed the `SENTRY_PERFORMANCE_MONITORING` compile flag requirement to access performance monitoring in the Sentry SDK. Performance monitoring is now available to everybody who has opted into the experimental API.
- New API to check whether the application has crashed in the previous run: `sentry_get_crashed_last_run()` and `sentry_clear_crashed_last_run()` ([#685](https://github.com/getsentry/sentry-native/pull/685)).
- Allow overriding the SDK name at build time - set the `SENTRY_SDK_NAME` CMake cache variable.

## 0.4.15
Expand Down
28 changes: 28 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,34 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_iter_headers(
sentry_transaction_t *tx, sentry_iter_headers_function_t callback,
void *userdata);

/**
* Returns whether the application has crashed on the last run.
*
* Notes:
* * The underlying value is set by sentry_init() - it must be called first.
* * Call sentry_clear_crashed_last_run() to reset for the next app run.
*
* Possible return values:
* 1 = the last run was a crash
* 0 = no crash recognized
* -1 = sentry_init() hasn't been called yet
*/
SENTRY_EXPERIMENTAL_API int sentry_get_crashed_last_run();

/**
* Clear the status of the "crashed-last-run". You should explicitly call
* this after sentry_init() if you're using sentry_get_crashed_last_run().
* Otherwise, the same information is reported on any subsequent runs.
*
* Notes:
* * This doesn't change the value of sentry_get_crashed_last_run() yet.
* However, if sentry_init() is called again, the value will change.
* * This may only be called after sentry_init() and before sentry_close().
*
* Returns 0 on success, 1 on error.
*/
SENTRY_EXPERIMENTAL_API int sentry_clear_crashed_last_run();

#ifdef __cplusplus
}
#endif
Expand Down
22 changes: 22 additions & 0 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
static sentry_options_t *g_options = NULL;
static sentry_mutex_t g_options_lock = SENTRY__MUTEX_INIT;

/// see sentry_get_crashed_last_run() for the possible values
static int g_last_crash = -1;

const sentry_options_t *
sentry__options_getref(void)
{
Expand Down Expand Up @@ -158,6 +161,7 @@ sentry_init(sentry_options_t *options)
last_crash = backend->get_last_crash_func(backend);
}

g_last_crash = sentry__has_crash_marker(options);
g_options = options;

// *after* setting the global options, trigger a scope and consent flush,
Expand Down Expand Up @@ -999,3 +1003,21 @@ sentry_span_finish(sentry_span_t *opaque_span)
sentry__span_free(opaque_span);
return;
}

int
sentry_get_crashed_last_run()
{
return g_last_crash;
}

int
sentry_clear_crashed_last_run()
{
bool success = false;
sentry_options_t *options = sentry__options_lock();
if (options) {
success = sentry__clear_crash_marker(options);
}
sentry__options_unlock();
return success ? 0 : 1;
}
35 changes: 34 additions & 1 deletion src/sentry_database.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ sentry__process_old_runs(const sentry_options_t *options, uint64_t last_crash)
sentry__capture_envelope(options->transport, session_envelope);
}

static const char *g_last_crash_filename = "last_crash";

bool
sentry__write_crash_marker(const sentry_options_t *options)
{
Expand All @@ -244,7 +246,7 @@ sentry__write_crash_marker(const sentry_options_t *options)
}

sentry_path_t *marker_path
= sentry__path_join_str(options->database_path, "last_crash");
= sentry__path_join_str(options->database_path, g_last_crash_filename);
if (!marker_path) {
sentry_free(iso_time);
return false;
Expand All @@ -260,3 +262,34 @@ sentry__write_crash_marker(const sentry_options_t *options)
}
return !rv;
}

bool
sentry__has_crash_marker(const sentry_options_t *options)
{
sentry_path_t *marker_path
= sentry__path_join_str(options->database_path, g_last_crash_filename);
if (!marker_path) {
return false;
}

bool result = sentry__path_is_file(marker_path);
sentry__path_free(marker_path);
return result;
}

bool
sentry__clear_crash_marker(const sentry_options_t *options)
{
sentry_path_t *marker_path
= sentry__path_join_str(options->database_path, g_last_crash_filename);
if (!marker_path) {
return false;
}

int rv = sentry__path_remove(marker_path);
sentry__path_free(marker_path);
if (rv) {
SENTRY_DEBUG("removing the crash timestamp file has failed");
}
return !rv;
}
10 changes: 10 additions & 0 deletions src/sentry_database.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,14 @@ void sentry__process_old_runs(
*/
bool sentry__write_crash_marker(const sentry_options_t *options);

/**
* This will check whether the `<database>/last_crash` file exists.
*/
bool sentry__has_crash_marker(const sentry_options_t *options);

/**
* This will remove the `<database>/last_crash` file.
*/
bool sentry__clear_crash_marker(const sentry_options_t *options);

#endif
69 changes: 69 additions & 0 deletions tests/unit/test_basic.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "sentry_core.h"
#include "sentry_database.h"
#include "sentry_testsupport.h"
#include "sentry_utils.h"

static void
send_envelope_test_basic(const sentry_envelope_t *envelope, void *data)
Expand Down Expand Up @@ -96,3 +98,70 @@ SENTRY_TEST(sampling_before_send)
// well, its random after all
TEST_CHECK(called_beforesend > 50 && called_beforesend < 100);
}

SENTRY_TEST(crash_marker)
{
sentry_options_t *options = sentry_options_new();

// clear returns true, regardless if the file exists
TEST_CHECK(sentry__clear_crash_marker(options));

// write should normally be true, even when called multiple times
TEST_CHECK(!sentry__has_crash_marker(options));
TEST_CHECK(sentry__write_crash_marker(options));
TEST_CHECK(sentry__has_crash_marker(options));
TEST_CHECK(sentry__write_crash_marker(options));
TEST_CHECK(sentry__has_crash_marker(options));

TEST_CHECK(sentry__clear_crash_marker(options));
TEST_CHECK(!sentry__has_crash_marker(options));
TEST_CHECK(sentry__clear_crash_marker(options));

sentry_options_free(options);
}

SENTRY_TEST(crashed_last_run)
{
// fails before init() is called
TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 1);

// clear any leftover from previous test runs
sentry_options_t *options = sentry_options_new();
TEST_CHECK(sentry__clear_crash_marker(options));
sentry_options_free(options);

// -1 before sentry_init()
TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), -1);

options = sentry_options_new();
sentry_options_set_dsn(options, "https://foo@sentry.invalid/42");
TEST_CHECK_INT_EQUAL(sentry_init(options), 0);
sentry_close();

TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 0);

options = sentry_options_new();
sentry_options_set_dsn(options, "https://foo@sentry.invalid/42");

// simulate a crash
TEST_CHECK(sentry__write_crash_marker(options));

TEST_CHECK_INT_EQUAL(sentry_init(options), 0);

TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1);

// clear the status and re-init
TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 0);

sentry_close();

// no change yet before sentry_init() is called
TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1);

options = sentry_options_new();
sentry_options_set_dsn(options, "https://foo@sentry.invalid/42");
TEST_CHECK_INT_EQUAL(sentry_init(options), 0);
sentry_close();

TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 0);
}
2 changes: 2 additions & 0 deletions tests/unit/tests.inc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ XX(child_spans)
XX(concurrent_init)
XX(concurrent_uninit)
XX(count_sampled_events)
XX(crash_marker)
XX(crashed_last_run)
XX(custom_logger)
XX(distributed_headers)
XX(drop_unfinished_spans)
Expand Down

0 comments on commit 9eecb1b

Please sign in to comment.