Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Android: Expose app-hang detection through the NDK bindings via `NdkOptions.setEnableAppHangTracking()` and `NdkOptions.setAppHangTimeoutMillis()`. ([#1823](https://github.com/getsentry/sentry-native/pull/1823))
- Windows: add wide-char versions of `sentry_capture_minidump` and `sentry_capture_minidump_n`. ([#1827](https://github.com/getsentry/sentry-native/pull/1827))
- Add `sentry_update_context` to allow updating already set context objects with new key-value pairs, as well as new values for existing keys. ([#1835](https://github.com/getsentry/sentry-native/pull/1835))

**Fixes**:

Expand Down
13 changes: 13 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -2300,6 +2300,19 @@ SENTRY_API void sentry_scope_set_context(
sentry_scope_t *scope, const char *key, sentry_value_t value);
SENTRY_API void sentry_scope_set_context_n(sentry_scope_t *scope,
const char *key, size_t key_len, sentry_value_t value);
/**
* Updates a context object by merging the provided values into it.
* Keys in `value` take precedence over keys in the context, updating the
* existing values. Keys in the existing context that are not present in `value`
* are preserved. If the context object does not exist yet, it will be created.
*/
SENTRY_API void sentry_update_context(const char *key, sentry_value_t value);
SENTRY_API void sentry_update_context_n(
const char *key, size_t key_len, sentry_value_t value);
SENTRY_API void sentry_scope_update_context(
sentry_scope_t *scope, const char *key, sentry_value_t value);
SENTRY_API void sentry_scope_update_context_n(sentry_scope_t *scope,
const char *key, size_t key_len, sentry_value_t value);

/**
* Removes the context object with the specified key.
Comment thread
sentry[bot] marked this conversation as resolved.
Expand Down
16 changes: 16 additions & 0 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,22 @@ sentry_set_context_n(const char *key, size_t key_len, sentry_value_t value)
}
}

void
sentry_update_context(const char *key, sentry_value_t value)
{
SENTRY_WITH_SCOPE_MUT (scope) {
sentry_scope_update_context(scope, key, value);
}
}

void
sentry_update_context_n(const char *key, size_t key_len, sentry_value_t value)
{
SENTRY_WITH_SCOPE_MUT (scope) {
sentry_scope_update_context_n(scope, key, key_len, value);
}
}

void
sentry__set_propagation_context(const char *key, sentry_value_t value)
{
Expand Down
22 changes: 22 additions & 0 deletions src/sentry_scope.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,28 @@ sentry_scope_set_context_n(sentry_scope_t *scope, const char *key,
sentry_value_set_by_key_n(scope->contexts, key, key_len, value);
}

void
sentry_scope_update_context(
sentry_scope_t *scope, const char *key, sentry_value_t value)
{
sentry_scope_update_context_n(
scope, key, sentry__guarded_strlen(key), value);
}

void
sentry_scope_update_context_n(sentry_scope_t *scope, const char *key,
size_t key_len, sentry_value_t value)
{
sentry_value_t context
= sentry_value_get_by_key_n(scope->contexts, key, key_len);
if (sentry_value_is_null(context)) {
sentry_value_set_by_key_n(scope->contexts, key, key_len, value);
} else {
sentry__value_merge_objects(value, context);
sentry_value_set_by_key_n(scope->contexts, key, key_len, value);
}
}

void
sentry__scope_set_fingerprint_va(
sentry_scope_t *scope, const char *fingerprint, va_list va)
Expand Down
84 changes: 84 additions & 0 deletions tests/unit/test_scope.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,90 @@ SENTRY_TEST(scope_contexts)
sentry_close();
}

SENTRY_TEST(scope_update_context)
{
SENTRY_TEST_OPTIONS_NEW(options);
sentry_init(options);

// update into empty: context does not exist yet
{
sentry_value_t device = sentry_value_new_object();
sentry_value_set_by_key(
device, "model", sentry_value_new_string("Xbox Series X"));
sentry_value_set_by_key(
device, "family", sentry_value_new_string("Xbox"));
sentry_update_context("device", device);

SENTRY_WITH_SCOPE (scope) {
sentry_value_t ctx
= sentry_value_get_by_key(scope->contexts, "device");
TEST_CHECK_STRING_EQUAL(
sentry_value_as_string(sentry_value_get_by_key(ctx, "model")),
"Xbox Series X");
TEST_CHECK_STRING_EQUAL(
sentry_value_as_string(sentry_value_get_by_key(ctx, "family")),
"Xbox");
}
}

// update should overwrite existing keys
{
sentry_value_t extra = sentry_value_new_object();
sentry_value_set_by_key(extra, "model", sentry_value_new_string("PC"));
sentry_value_set_by_key(
extra, "cpu_description", sentry_value_new_string("some cpu"));
sentry_update_context("device", extra);

SENTRY_WITH_SCOPE (scope) {
sentry_value_t ctx
= sentry_value_get_by_key(scope->contexts, "device");
TEST_CHECK_STRING_EQUAL(
sentry_value_as_string(sentry_value_get_by_key(ctx, "model")),
"PC");
TEST_CHECK_STRING_EQUAL(
sentry_value_as_string(sentry_value_get_by_key(ctx, "family")),
"Xbox");
TEST_CHECK_STRING_EQUAL(
sentry_value_as_string(
sentry_value_get_by_key(ctx, "cpu_description")),
"some cpu");
}
}

// scoped update into empty
{
sentry_scope_t *local_scope = sentry_local_scope_new();

sentry_value_t os = sentry_value_new_object();
sentry_value_set_by_key(os, "name", sentry_value_new_string("SteamOS"));
sentry_scope_update_context(local_scope, "os", os);

sentry_value_t ctx
= sentry_value_get_by_key(local_scope->contexts, "os");
TEST_CHECK_STRING_EQUAL(
sentry_value_as_string(sentry_value_get_by_key(ctx, "name")),
"SteamOS");

// scoped update overwrites existing keys
sentry_value_t os2 = sentry_value_new_object();
sentry_value_set_by_key(os2, "name", sentry_value_new_string("Linux"));
sentry_value_set_by_key(os2, "version", sentry_value_new_string("6.1"));
sentry_scope_update_context(local_scope, "os", os2);

ctx = sentry_value_get_by_key(local_scope->contexts, "os");
TEST_CHECK_STRING_EQUAL(
sentry_value_as_string(sentry_value_get_by_key(ctx, "name")),
"Linux");
TEST_CHECK_STRING_EQUAL(
sentry_value_as_string(sentry_value_get_by_key(ctx, "version")),
"6.1");

sentry__scope_free(local_scope);
}

sentry_close();
}

SENTRY_TEST(scope_extra)
{
SENTRY_TEST_OPTIONS_NEW(options);
Expand Down
1 change: 1 addition & 0 deletions tests/unit/tests.inc
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ XX(sampling_decision)
XX(sampling_transaction)
XX(scope_breadcrumbs)
XX(scope_contexts)
XX(scope_update_context)
XX(scope_extra)
XX(scope_fingerprint)
XX(scope_fingerprint_n)
Expand Down
Loading