From bce6e8b44f5f9b32135187e31a79a1fdb57c2dfd Mon Sep 17 00:00:00 2001 From: JoshuaMoelans <60878493+JoshuaMoelans@users.noreply.github.com> Date: Tue, 14 Jan 2025 16:42:25 +0100 Subject: [PATCH] feat: add `traces_sampler` (#1108) * add traces_sampler option * update CHANGELOG.md * introduced `sentry_traces_sampler_function` typedef * added sampling context * format * eof newlines * feat: pass sampling_context into sampling decision * remove unnecessary commented include * add memory freeing/incref-decref * change custom sampling context type to sentry_value_t * add decref * removed unneeded creation function * format * set codeql runner to ubuntu-22.04 * take ownership of custom_sampling_ctx * add parent sampling decision * add traces_sampler and parent sampling decision tests * decref * change callback arg from struct to parameter list * format * mark unused parameters * format * cleanup test + docs * apply PR feedback * format * cleanup example * add getters for transaction_ctx name + operation * remove (void) on transaction_ctx in example.c * add transaction_ctx getter tests * dont expose sampling_context_s in sentry.h * change bool to int * cleanup example.c * refactor tx_cxt to tx_ctx convention * change sampled_int init --------- Co-authored-by: Mischan Toosarani-Hausberger --- CHANGELOG.md | 1 + CONTRIBUTING.md | 2 + examples/example.c | 36 +++++++- include/sentry.h | 62 +++++++++----- src/CMakeLists.txt | 1 + src/sentry_core.c | 73 ++++++++++------ src/sentry_core.h | 4 +- src/sentry_options.c | 7 ++ src/sentry_options.h | 1 + src/sentry_sampling_context.h | 13 +++ src/sentry_tracing.c | 84 ++++++++++-------- src/sentry_tracing.h | 2 +- tests/unit/test_sampling.c | 126 +++++++++++++++++++++++++-- tests/unit/test_tracing.c | 156 +++++++++++++++++----------------- 14 files changed, 397 insertions(+), 171 deletions(-) create mode 100644 src/sentry_sampling_context.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b54f7a77..d8771e118 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Add support for Xbox Series X/S. ([#1100](https://github.com/getsentry/sentry-native/pull/1100)) - Add option to set debug log level. ([#1107](https://github.com/getsentry/sentry-native/pull/1107)) +- Add `traces_sampler` ([#1108](https://github.com/getsentry/sentry-native/pull/1108)) - Provide support for C++17 compilers when using the `crashpad` backend. ([#1110](https://github.com/getsentry/sentry-native/pull/1110), [crashpad#116](https://github.com/getsentry/crashpad/pull/116), [mini_chromium#1](https://github.com/getsentry/mini_chromium/pull/1)) ## 0.7.17 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 041d99d24..01585ad9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -148,6 +148,8 @@ The example currently supports the following commands: - `stack-overflow`: Provokes a stack-overflow. - `http-proxy`: Uses a localhost `HTTP` proxy on port 8080. - `socks5-proxy`: Uses a localhost `SOCKS5` proxy on port 1080. +- `capture-transaction`: Captures a transaction. +- `traces-sampler`: Installs a traces sampler callback function when used alongside `capture-transaction`. Only on Windows using crashpad with its WER handler module: diff --git a/examples/example.c b/examples/example.c index a0c789dfb..6e48ed8a5 100644 --- a/examples/example.c +++ b/examples/example.c @@ -30,6 +30,32 @@ # define sleep_s(SECONDS) sleep(SECONDS) #endif +static double +traces_sampler_callback(const sentry_transaction_context_t *transaction_ctx, + sentry_value_t custom_sampling_ctx, const int *parent_sampled) +{ + if (parent_sampled != NULL) { + if (*parent_sampled) { + return 0.8; // high sample rate for children of sampled transactions + } + return 0; // parent is not sampled + } + if (strcmp(sentry_transaction_context_get_name(transaction_ctx), + "little.teapot") + == 0) { + if (strcmp(sentry_transaction_context_get_operation(transaction_ctx), + "Short and stout here is my handle and here is my spout") + == 0) { + if (sentry_value_as_int32( + sentry_value_get_by_key(custom_sampling_ctx, "b")) + == 42) { + return 1; + } + } + } + return 0; +} + static sentry_value_t before_send_callback(sentry_value_t event, void *hint, void *closure) { @@ -234,6 +260,10 @@ main(int argc, char **argv) options, discarding_on_crash_callback, NULL); } + if (has_arg(argc, argv, "traces-sampler")) { + sentry_options_set_traces_sampler(options, traces_sampler_callback); + } + if (has_arg(argc, argv, "override-sdk-name")) { sentry_options_set_sdk_name(options, "sentry.native.android.flutter"); } @@ -405,8 +435,12 @@ main(int argc, char **argv) if (has_arg(argc, argv, "unsample-tx")) { sentry_transaction_context_set_sampled(tx_ctx, 0); } + + sentry_value_t custom_sampling_ctx = sentry_value_new_object(); + sentry_value_set_by_key( + custom_sampling_ctx, "b", sentry_value_new_int32(42)); sentry_transaction_t *tx - = sentry_transaction_start(tx_ctx, sentry_value_new_null()); + = sentry_transaction_start(tx_ctx, custom_sampling_ctx); sentry_transaction_set_data( tx, "url", sentry_value_new_string("https://example.com")); diff --git a/include/sentry.h b/include/sentry.h index e50f61a75..c8cf300f4 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -1533,6 +1533,26 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_traces_sample_rate( SENTRY_EXPERIMENTAL_API double sentry_options_get_traces_sample_rate( sentry_options_t *opts); +/** + * A sentry Transaction Context. + * + * See Transaction Interface under + * https://develop.sentry.dev/sdk/performance/#new-span-and-transaction-classes + */ +struct sentry_transaction_context_s; +typedef struct sentry_transaction_context_s sentry_transaction_context_t; +typedef double (*sentry_traces_sampler_function)( + const sentry_transaction_context_t *transaction_ctx, + sentry_value_t custom_sampling_ctx, const int *parent_sampled); + +/** + * Sets the traces sampler callback. Should be a function that returns a double + * and takes in a sentry_transaction_context_t pointer, a sentry_value_t for + * a custom sampling context and a int pointer for the parent sampled flag. + */ +SENTRY_EXPERIMENTAL_API void sentry_options_set_traces_sampler( + sentry_options_t *opts, sentry_traces_sampler_function callback); + #ifdef SENTRY_PLATFORM_LINUX /** @@ -1590,15 +1610,6 @@ SENTRY_EXPERIMENTAL_API void sentry_end_session_with_status( /* -- Performance Monitoring/Tracing APIs -- */ -/** - * A sentry Transaction Context. - * - * See Transaction Interface under - * https://develop.sentry.dev/sdk/performance/#new-span-and-transaction-classes - */ -struct sentry_transaction_context_s; -typedef struct sentry_transaction_context_s sentry_transaction_context_t; - /** * A sentry Transaction. * @@ -1649,9 +1660,14 @@ sentry_transaction_context_new_n(const char *name, size_t name_len, * setting a name on it. */ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_name( - sentry_transaction_context_t *tx_cxt, const char *name); + sentry_transaction_context_t *tx_ctx, const char *name); SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_name_n( - sentry_transaction_context_t *tx_cxt, const char *name, size_t name_len); + sentry_transaction_context_t *tx_ctx, const char *name, size_t name_len); +/** + * Gets the `name` of a Transaction Context. + */ +SENTRY_EXPERIMENTAL_API const char *sentry_transaction_context_get_name( + const sentry_transaction_context_t *tx_ctx); /** * Sets the `operation` on a Transaction Context, which will be used in the @@ -1664,10 +1680,15 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_name_n( * setting an operation on it. */ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_operation( - sentry_transaction_context_t *tx_cxt, const char *operation); + sentry_transaction_context_t *tx_ctx, const char *operation); SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_operation_n( - sentry_transaction_context_t *tx_cxt, const char *operation, + sentry_transaction_context_t *tx_ctx, const char *operation, size_t operation_len); +/** + * Gets the `operation` of a Transaction Context. + */ +SENTRY_EXPERIMENTAL_API const char *sentry_transaction_context_get_operation( + const sentry_transaction_context_t *tx_ctx); /** * Sets the `sampled` field on a Transaction Context, which will be used in the @@ -1681,7 +1702,7 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_operation_n( * setting `sampled` on it. */ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_sampled( - sentry_transaction_context_t *tx_cxt, int sampled); + sentry_transaction_context_t *tx_ctx, int sampled); /** * Removes the `sampled` field on a Transaction Context, which will be used in @@ -1693,7 +1714,7 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_sampled( * removing `sampled`. */ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_remove_sampled( - sentry_transaction_context_t *tx_cxt); + sentry_transaction_context_t *tx_ctx); /** * Update the Transaction Context with the given HTTP header key/value pair. @@ -1704,9 +1725,9 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_remove_sampled( * upstream service. */ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_update_from_header( - sentry_transaction_context_t *tx_cxt, const char *key, const char *value); + sentry_transaction_context_t *tx_ctx, const char *key, const char *value); SENTRY_EXPERIMENTAL_API void sentry_transaction_context_update_from_header_n( - sentry_transaction_context_t *tx_cxt, const char *key, size_t key_len, + sentry_transaction_context_t *tx_ctx, const char *key, size_t key_len, const char *value, size_t value_len); /** @@ -1735,6 +1756,9 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_update_from_header_n( * Takes ownership of `transaction_context`. A Transaction Context cannot be * modified or re-used after it is used to start a Transaction. * + * Takes ownership of `custom_sampling_ctx`. A Sampling Context cannot be + * modified or re-used after it is used to start a Transaction. + * * The returned value is not thread-safe. Users are expected to ensure that * appropriate locking mechanisms are implemented over the Transaction if it * needs to be mutated across threads. Methods operating on the Transaction will @@ -1742,7 +1766,7 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_update_from_header_n( * the object in a thread-safe way. */ SENTRY_EXPERIMENTAL_API sentry_transaction_t *sentry_transaction_start( - sentry_transaction_context_t *tx_cxt, sentry_value_t sampling_ctx); + sentry_transaction_context_t *tx_ctx, sentry_value_t custom_sampling_ctx); /** * Also starts a transaction like the regular `sentry_transaction_start` * function, but has an additional timestamp parameter to let the user provide @@ -1751,7 +1775,7 @@ SENTRY_EXPERIMENTAL_API sentry_transaction_t *sentry_transaction_start( * The timestamp should be provided in microseconds since the Unix epoch. */ SENTRY_EXPERIMENTAL_API sentry_transaction_t *sentry_transaction_start_ts( - sentry_transaction_context_t *tx_cxt, sentry_value_t sampling_ctx, + sentry_transaction_context_t *tx_ctx, sentry_value_t custom_sampling_ctx, uint64_t timestamp); /** diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a7ba5949..226368b19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,7 @@ sentry_target_sources_cwd(sentry sentry_random.h sentry_ratelimiter.c sentry_ratelimiter.h + sentry_sampling_context.h sentry_scope.c sentry_scope.h sentry_session.c diff --git a/src/sentry_core.c b/src/sentry_core.c index 57d30b415..f37a281e1 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -448,18 +448,39 @@ sentry__capture_event(sentry_value_t event) } bool -sentry__should_send_transaction(sentry_value_t tx_cxt) -{ - sentry_value_t context_setting = sentry_value_get_by_key(tx_cxt, "sampled"); - if (!sentry_value_is_null(context_setting)) { - return sentry_value_is_true(context_setting); - } - +sentry__should_send_transaction( + sentry_value_t tx_ctx, sentry_sampling_context_t *sampling_ctx) +{ + sentry_value_t context_setting = sentry_value_get_by_key(tx_ctx, "sampled"); + bool sampled = sentry_value_is_null(context_setting) + ? false + : sentry_value_is_true(context_setting); + sampling_ctx->parent_sampled + = sentry_value_is_null(context_setting) ? NULL : &sampled; + + const int parent_sampled_int = sampling_ctx->parent_sampled + ? (int)*sampling_ctx->parent_sampled + : -1; // -1 signifies no parent sampling decision bool send = false; SENTRY_WITH_OPTIONS (options) { - send = sentry__roll_dice(options->traces_sample_rate); - // TODO(tracing): Run through traces sampler function if rate is - // unavailable. + if (options->traces_sampler) { + const double result + = ((sentry_traces_sampler_function)options->traces_sampler)( + sampling_ctx->transaction_context, + sampling_ctx->custom_sampling_context, + sampling_ctx->parent_sampled == NULL ? NULL + : &parent_sampled_int); + send = sentry__roll_dice(result); + } else { + if (sampling_ctx->parent_sampled != NULL) { + send = *sampling_ctx->parent_sampled; + } else { + send = sentry__roll_dice(options->traces_sample_rate); + } + } + } + if (sampling_ctx->parent_sampled != NULL) { + sampling_ctx->parent_sampled = NULL; } return send; } @@ -840,32 +861,28 @@ sentry_set_level(sentry_level_t level) } sentry_transaction_t * -sentry_transaction_start( - sentry_transaction_context_t *opaque_tx_cxt, sentry_value_t sampling_ctx) +sentry_transaction_start(sentry_transaction_context_t *opaque_tx_ctx, + sentry_value_t custom_sampling_ctx) { return sentry_transaction_start_ts( - opaque_tx_cxt, sampling_ctx, sentry__usec_time()); + opaque_tx_ctx, custom_sampling_ctx, sentry__usec_time()); } sentry_transaction_t * -sentry_transaction_start_ts(sentry_transaction_context_t *opaque_tx_cxt, - sentry_value_t sampling_ctx, uint64_t timestamp) +sentry_transaction_start_ts(sentry_transaction_context_t *opaque_tx_ctx, + sentry_value_t custom_sampling_ctx, uint64_t timestamp) { - // Just free this immediately until we implement proper support for - // traces_sampler. - sentry_value_decref(sampling_ctx); - - if (!opaque_tx_cxt) { + if (!opaque_tx_ctx) { return NULL; } - sentry_value_t tx_cxt = opaque_tx_cxt->inner; + sentry_value_t tx_ctx = opaque_tx_ctx->inner; // If the parent span ID is some empty-ish value, just remove it sentry_value_t parent_span - = sentry_value_get_by_key(tx_cxt, "parent_span_id"); + = sentry_value_get_by_key(tx_ctx, "parent_span_id"); if (sentry_value_get_length(parent_span) < 1) { - sentry_value_remove_by_key(tx_cxt, "parent_span_id"); + sentry_value_remove_by_key(tx_ctx, "parent_span_id"); } // The ending timestamp is stripped to avoid misleading ourselves later @@ -874,17 +891,19 @@ sentry_transaction_start_ts(sentry_transaction_context_t *opaque_tx_cxt, sentry_value_t tx = sentry_value_new_event(); sentry_value_remove_by_key(tx, "timestamp"); - sentry__value_merge_objects(tx, tx_cxt); - - bool should_sample = sentry__should_send_transaction(tx_cxt); + sentry__value_merge_objects(tx, tx_ctx); + sentry_sampling_context_t sampling_ctx + = { opaque_tx_ctx, custom_sampling_ctx, NULL }; + bool should_sample = sentry__should_send_transaction(tx_ctx, &sampling_ctx); sentry_value_set_by_key( tx, "sampled", sentry_value_new_bool(should_sample)); + sentry_value_decref(custom_sampling_ctx); sentry_value_set_by_key(tx, "start_timestamp", sentry__value_new_string_owned( sentry__usec_time_to_iso8601(timestamp))); - sentry__transaction_context_free(opaque_tx_cxt); + sentry__transaction_context_free(opaque_tx_ctx); return sentry__transaction_new(tx); } diff --git a/src/sentry_core.h b/src/sentry_core.h index 1b35f92ef..6e12d24a7 100644 --- a/src/sentry_core.h +++ b/src/sentry_core.h @@ -3,6 +3,7 @@ #include "sentry_boot.h" #include "sentry_logger.h" +#include "sentry_sampling_context.h" #define SENTRY_BREADCRUMBS_MAX 100 #define SENTRY_SPANS_MAX 1000 @@ -117,7 +118,8 @@ void sentry__options_unlock(void); // these for now are only needed outside of core for tests #ifdef SENTRY_UNITTEST bool sentry__roll_dice(double probability); -bool sentry__should_send_transaction(sentry_value_t tx_cxt); +bool sentry__should_send_transaction( + sentry_value_t tx_ctx, sentry_sampling_context_t *sampling_ctx); #endif #endif diff --git a/src/sentry_options.c b/src/sentry_options.c index 0cad8e335..60db87a28 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -615,6 +615,13 @@ sentry_options_get_traces_sample_rate(sentry_options_t *opts) return opts->traces_sample_rate; } +void +sentry_options_set_traces_sampler( + sentry_options_t *opts, sentry_traces_sampler_function callback) +{ + opts->traces_sampler = callback; +} + void sentry_options_set_backend(sentry_options_t *opts, sentry_backend_t *backend) { diff --git a/src/sentry_options.h b/src/sentry_options.h index 07a2fdbe6..521e9e5e1 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -61,6 +61,7 @@ typedef struct sentry_options_s { /* Experimentally exposed */ double traces_sample_rate; + sentry_traces_sampler_function traces_sampler; size_t max_spans; /* everything from here on down are options which are stored here but diff --git a/src/sentry_sampling_context.h b/src/sentry_sampling_context.h new file mode 100644 index 000000000..431c1a36d --- /dev/null +++ b/src/sentry_sampling_context.h @@ -0,0 +1,13 @@ +// sentry_sampling_context.h +#ifndef SENTRY_SAMPLING_CONTEXT_H_INCLUDED +#define SENTRY_SAMPLING_CONTEXT_H_INCLUDED + +#include "sentry_tracing.h" + +typedef struct sentry_sampling_context_s { + sentry_transaction_context_t *transaction_context; + sentry_value_t custom_sampling_context; + bool *parent_sampled; +} sentry_sampling_context_t; + +#endif // SENTRY_SAMPLING_CONTEXT_H_INCLUDED diff --git a/src/sentry_tracing.c b/src/sentry_tracing.c index 81684af4f..185b61797 100644 --- a/src/sentry_tracing.c +++ b/src/sentry_tracing.c @@ -55,21 +55,21 @@ sentry_transaction_context_t * sentry_transaction_context_new_n(const char *name, size_t name_len, const char *operation, size_t operation_len) { - sentry_transaction_context_t *tx_cxt + sentry_transaction_context_t *tx_ctx = SENTRY_MAKE(sentry_transaction_context_t); - if (!tx_cxt) { + if (!tx_ctx) { return NULL; } - tx_cxt->inner = sentry__value_transaction_context_new_n( + tx_ctx->inner = sentry__value_transaction_context_new_n( (sentry_slice_t) { name, name_len }, (sentry_slice_t) { operation, operation_len }); - if (sentry_value_is_null(tx_cxt->inner)) { - sentry_free(tx_cxt); + if (sentry_value_is_null(tx_ctx->inner)) { + sentry_free(tx_ctx); return NULL; } - return tx_cxt; + return tx_ctx; } sentry_transaction_context_t * @@ -80,74 +80,88 @@ sentry_transaction_context_new(const char *name, const char *operation) } void -sentry__transaction_context_free(sentry_transaction_context_t *tx_cxt) +sentry__transaction_context_free(sentry_transaction_context_t *tx_ctx) { - if (!tx_cxt) { + if (!tx_ctx) { return; } - if (sentry_value_refcount(tx_cxt->inner) <= 1) { - sentry_value_decref(tx_cxt->inner); - sentry_free(tx_cxt); + if (sentry_value_refcount(tx_ctx->inner) <= 1) { + sentry_value_decref(tx_ctx->inner); + sentry_free(tx_ctx); } else { - sentry_value_decref(tx_cxt->inner); + sentry_value_decref(tx_ctx->inner); } } void sentry_transaction_context_set_name( - sentry_transaction_context_t *tx_cxt, const char *name) + sentry_transaction_context_t *tx_ctx, const char *name) { - if (tx_cxt) { + if (tx_ctx) { sentry_value_set_by_key( - tx_cxt->inner, "transaction", sentry_value_new_string(name)); + tx_ctx->inner, "transaction", sentry_value_new_string(name)); } } void sentry_transaction_context_set_name_n( - sentry_transaction_context_t *tx_cxt, const char *name, size_t name_len) + sentry_transaction_context_t *tx_ctx, const char *name, size_t name_len) { - if (tx_cxt) { - sentry_value_set_by_key(tx_cxt->inner, "transaction", + if (tx_ctx) { + sentry_value_set_by_key(tx_ctx->inner, "transaction", sentry_value_new_string_n(name, name_len)); } } +const char * +sentry_transaction_context_get_name(const sentry_transaction_context_t *tx_ctx) +{ + return sentry_value_as_string( + sentry_value_get_by_key(tx_ctx->inner, "transaction")); +} + void sentry_transaction_context_set_operation( - sentry_transaction_context_t *tx_cxt, const char *operation) + sentry_transaction_context_t *tx_ctx, const char *operation) { - if (tx_cxt) { + if (tx_ctx) { sentry_value_set_by_key( - tx_cxt->inner, "op", sentry_value_new_string(operation)); + tx_ctx->inner, "op", sentry_value_new_string(operation)); } } void -sentry_transaction_context_set_operation_n(sentry_transaction_context_t *tx_cxt, +sentry_transaction_context_set_operation_n(sentry_transaction_context_t *tx_ctx, const char *operation, size_t operation_len) { - if (tx_cxt) { - sentry_value_set_by_key(tx_cxt->inner, "op", + if (tx_ctx) { + sentry_value_set_by_key(tx_ctx->inner, "op", sentry_value_new_string_n(operation, operation_len)); } } +const char * +sentry_transaction_context_get_operation( + const sentry_transaction_context_t *tx_ctx) +{ + return sentry_value_as_string(sentry_value_get_by_key(tx_ctx->inner, "op")); +} + void sentry_transaction_context_set_sampled( - sentry_transaction_context_t *tx_cxt, int sampled) + sentry_transaction_context_t *tx_ctx, int sampled) { - if (tx_cxt) { + if (tx_ctx) { sentry_value_set_by_key( - tx_cxt->inner, "sampled", sentry_value_new_bool(sampled)); + tx_ctx->inner, "sampled", sentry_value_new_bool(sampled)); } } void -sentry_transaction_context_remove_sampled(sentry_transaction_context_t *tx_cxt) +sentry_transaction_context_remove_sampled(sentry_transaction_context_t *tx_ctx) { - if (tx_cxt) { - sentry_value_remove_by_key(tx_cxt->inner, "sampled"); + if (tx_ctx) { + sentry_value_remove_by_key(tx_ctx->inner, "sampled"); } } @@ -197,10 +211,10 @@ is_valid_span_id(const char *span_id) void sentry_transaction_context_update_from_header_n( - sentry_transaction_context_t *tx_cxt, const char *key, size_t key_len, + sentry_transaction_context_t *tx_ctx, const char *key, size_t key_len, const char *value, size_t value_len) { - if (!tx_cxt) { + if (!tx_ctx) { return; } @@ -225,7 +239,7 @@ sentry_transaction_context_update_from_header_n( return; } - sentry_value_t inner = tx_cxt->inner; + sentry_value_t inner = tx_ctx->inner; char *s = sentry__string_clone_n(trace_id_start, trace_id_end - trace_id_start); @@ -264,9 +278,9 @@ sentry_transaction_context_update_from_header_n( void sentry_transaction_context_update_from_header( - sentry_transaction_context_t *tx_cxt, const char *key, const char *value) + sentry_transaction_context_t *tx_ctx, const char *key, const char *value) { - sentry_transaction_context_update_from_header_n(tx_cxt, key, + sentry_transaction_context_update_from_header_n(tx_ctx, key, sentry__guarded_strlen(key), value, sentry__guarded_strlen(value)); } diff --git a/src/sentry_tracing.h b/src/sentry_tracing.h index 5884e8731..814f98f23 100644 --- a/src/sentry_tracing.h +++ b/src/sentry_tracing.h @@ -27,7 +27,7 @@ typedef struct sentry_transaction_s { sentry_value_t inner; } sentry_transaction_t; -void sentry__transaction_context_free(sentry_transaction_context_t *tx_cxt); +void sentry__transaction_context_free(sentry_transaction_context_t *tx_ctx); sentry_transaction_t *sentry__transaction_new(sentry_value_t inner); void sentry__transaction_incref(sentry_transaction_t *tx); diff --git a/tests/unit/test_sampling.c b/tests/unit/test_sampling.c index 749c5515f..95be5da9e 100644 --- a/tests/unit/test_sampling.c +++ b/tests/unit/test_sampling.c @@ -1,3 +1,5 @@ +#include "sentry_options.h" +#include "sentry_sampling_context.h" #include "sentry_testsupport.h" #include "sentry_tracing.h" @@ -8,30 +10,136 @@ SENTRY_TEST(sampling_decision) TEST_CHECK(sentry__roll_dice(2.0)); } +static double +traces_sampler_callback(const sentry_transaction_context_t *transaction_ctx, + sentry_value_t custom_sampling_ctx, const int *parent_sampled) +{ + const char *name = sentry_transaction_context_get_name(transaction_ctx); + const char *operation + = sentry_transaction_context_get_operation(transaction_ctx); + + if (strcmp(name, "skipme") == 0) { + return 0.0; + } + if (strcmp(name, "sampleme") == 0) { + return 1.0; + } + if (strcmp(operation, "skipme") == 0) { + return 0.0; + } + if (strcmp(operation, "sampleme") == 0) { + return 1.0; + } + if (parent_sampled != NULL) { + if (*parent_sampled) { + return 1; // high sample rate for children of sampled transactions + } + return 0; // parent is not sampled + } + if (sentry_value_as_int32( + sentry_value_get_by_key(custom_sampling_ctx, "answer")) + == 42) { + return 1; + } + return 0; +} + SENTRY_TEST(sampling_transaction) { sentry_options_t *options = sentry_options_new(); TEST_CHECK(sentry_init(options) == 0); - sentry_transaction_context_t *tx_cxt + sentry_transaction_context_t *tx_ctx = sentry_transaction_context_new("honk", NULL); - sentry_transaction_context_set_sampled(tx_cxt, 0); - TEST_CHECK(sentry__should_send_transaction(tx_cxt->inner) == false); + sentry_transaction_context_set_sampled(tx_ctx, 0); + sentry_sampling_context_t sampling_ctx + = { tx_ctx, sentry_value_new_null(), NULL }; + TEST_CHECK( + sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx) == false); - sentry_transaction_context_set_sampled(tx_cxt, 1); - TEST_CHECK(sentry__should_send_transaction(tx_cxt->inner)); + sentry_transaction_context_set_sampled(tx_ctx, 1); + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); // fall back to default in sentry options (0.0) if sampled isn't there - sentry_transaction_context_remove_sampled(tx_cxt); - TEST_CHECK(sentry__should_send_transaction(tx_cxt->inner) == false); + sentry_transaction_context_remove_sampled(tx_ctx); + TEST_CHECK( + sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx) == false); + + // sampled parent -> sampled child + sentry_transaction_context_set_sampled(tx_ctx, 1); + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); options = sentry_options_new(); sentry_options_set_traces_sample_rate(options, 1.0); TEST_CHECK(sentry_init(options) == 0); - TEST_CHECK(sentry__should_send_transaction(tx_cxt->inner)); + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); + + // non-sampled parent + sentry_transaction_context_set_sampled(tx_ctx, 0); + TEST_CHECK( + sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx) == false); + + sentry_transaction_context_remove_sampled(tx_ctx); + + // test the traces_sampler callback + options = sentry_options_new(); + sentry_options_set_traces_sampler(options, traces_sampler_callback); + sentry_options_set_traces_sample_rate(options, 1.0); + TEST_CHECK(sentry_init(options) == 0); + + sentry_value_t custom_sampling_ctx = sentry_value_new_object(); + sentry_value_set_by_key( + custom_sampling_ctx, "answer", sentry_value_new_int32(42)); + sampling_ctx.custom_sampling_context = custom_sampling_ctx; + + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); + + // non-sampled parent and traces sampler + sentry_transaction_context_set_sampled(tx_ctx, 0); + TEST_CHECK( + sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx) == false); + // removing sampled should fall back to traces sampler + sentry_transaction_context_remove_sampled(tx_ctx); + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); + sentry_value_set_by_key( + custom_sampling_ctx, "answer", sentry_value_new_int32(21)); + TEST_CHECK( + sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx) == false); + + // sampled parent and traces sampler + sentry_transaction_context_set_sampled(tx_ctx, 1); + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); + sentry_transaction_context_remove_sampled(tx_ctx); + + // testing transaction_context getters + sentry_transaction_context_set_name(tx_ctx, "skipme"); + TEST_CHECK_STRING_EQUAL( + sentry_transaction_context_get_name(tx_ctx), "skipme"); + TEST_CHECK( + sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx) == false); + sentry_transaction_context_set_name(tx_ctx, "sampleme"); + TEST_CHECK_STRING_EQUAL( + sentry_transaction_context_get_name(tx_ctx), "sampleme"); + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); + sentry_transaction_context_set_name(tx_ctx, ""); // reset name + + sentry_transaction_context_set_operation(tx_ctx, "skipme"); + TEST_CHECK( + sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx) == false); + sentry_transaction_context_set_operation(tx_ctx, "sampleme"); + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); + + // remove traces_sampler callback, should fall back to traces_sample_rate + options->traces_sampler = NULL; + sentry_options_set_traces_sample_rate(options, 0.0); + TEST_CHECK( + sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx) == false); + sentry_options_set_traces_sample_rate(options, 1.0); + TEST_CHECK(sentry__should_send_transaction(tx_ctx->inner, &sampling_ctx)); - sentry__transaction_context_free(tx_cxt); + sentry__transaction_context_free(tx_ctx); + sentry_value_decref(custom_sampling_ctx); sentry_close(); } diff --git a/tests/unit/test_tracing.c b/tests/unit/test_tracing.c index 23d5f9a7d..33871f42f 100644 --- a/tests/unit/test_tracing.c +++ b/tests/unit/test_tracing.c @@ -52,70 +52,70 @@ SENTRY_TEST(basic_tracing_context) SENTRY_TEST(basic_transaction) { - sentry_transaction_context_t *opaque_tx_cxt + sentry_transaction_context_t *opaque_tx_ctx = sentry_transaction_context_new(NULL, NULL); - sentry_value_t tx_cxt; - if (opaque_tx_cxt != NULL) { - tx_cxt = opaque_tx_cxt->inner; - TEST_CHECK(!sentry_value_is_null(tx_cxt)); - CHECK_STRING_PROPERTY(tx_cxt, "transaction", ""); - CHECK_STRING_PROPERTY(tx_cxt, "op", ""); - TEST_CHECK(!IS_NULL(tx_cxt, "trace_id")); - TEST_CHECK(!IS_NULL(tx_cxt, "span_id")); + sentry_value_t tx_ctx; + if (opaque_tx_ctx != NULL) { + tx_ctx = opaque_tx_ctx->inner; + TEST_CHECK(!sentry_value_is_null(tx_ctx)); + CHECK_STRING_PROPERTY(tx_ctx, "transaction", ""); + CHECK_STRING_PROPERTY(tx_ctx, "op", ""); + TEST_CHECK(!IS_NULL(tx_ctx, "trace_id")); + TEST_CHECK(!IS_NULL(tx_ctx, "span_id")); } else { - TEST_CHECK(opaque_tx_cxt != NULL); + TEST_CHECK(opaque_tx_ctx != NULL); } - sentry__transaction_context_free(opaque_tx_cxt); + sentry__transaction_context_free(opaque_tx_ctx); - opaque_tx_cxt = sentry_transaction_context_new("", ""); - if (opaque_tx_cxt != NULL) { - tx_cxt = opaque_tx_cxt->inner; - TEST_CHECK(!sentry_value_is_null(tx_cxt)); - CHECK_STRING_PROPERTY(tx_cxt, "transaction", ""); - CHECK_STRING_PROPERTY(tx_cxt, "op", ""); - TEST_CHECK(!IS_NULL(tx_cxt, "trace_id")); - TEST_CHECK(!IS_NULL(tx_cxt, "span_id")); + opaque_tx_ctx = sentry_transaction_context_new("", ""); + if (opaque_tx_ctx != NULL) { + tx_ctx = opaque_tx_ctx->inner; + TEST_CHECK(!sentry_value_is_null(tx_ctx)); + CHECK_STRING_PROPERTY(tx_ctx, "transaction", ""); + CHECK_STRING_PROPERTY(tx_ctx, "op", ""); + TEST_CHECK(!IS_NULL(tx_ctx, "trace_id")); + TEST_CHECK(!IS_NULL(tx_ctx, "span_id")); } else { - TEST_CHECK(opaque_tx_cxt != NULL); + TEST_CHECK(opaque_tx_ctx != NULL); } - sentry__transaction_context_free(opaque_tx_cxt); + sentry__transaction_context_free(opaque_tx_ctx); - opaque_tx_cxt = sentry_transaction_context_new("honk.beep", "beepbeep"); - if (opaque_tx_cxt != NULL) { - tx_cxt = opaque_tx_cxt->inner; - TEST_CHECK(!sentry_value_is_null(tx_cxt)); - CHECK_STRING_PROPERTY(tx_cxt, "transaction", "honk.beep"); - CHECK_STRING_PROPERTY(tx_cxt, "op", "beepbeep"); - TEST_CHECK(!IS_NULL(tx_cxt, "trace_id")); - TEST_CHECK(!IS_NULL(tx_cxt, "span_id")); + opaque_tx_ctx = sentry_transaction_context_new("honk.beep", "beepbeep"); + if (opaque_tx_ctx != NULL) { + tx_ctx = opaque_tx_ctx->inner; + TEST_CHECK(!sentry_value_is_null(tx_ctx)); + CHECK_STRING_PROPERTY(tx_ctx, "transaction", "honk.beep"); + CHECK_STRING_PROPERTY(tx_ctx, "op", "beepbeep"); + TEST_CHECK(!IS_NULL(tx_ctx, "trace_id")); + TEST_CHECK(!IS_NULL(tx_ctx, "span_id")); - sentry_transaction_context_set_name(opaque_tx_cxt, ""); - CHECK_STRING_PROPERTY(tx_cxt, "transaction", ""); + sentry_transaction_context_set_name(opaque_tx_ctx, ""); + CHECK_STRING_PROPERTY(tx_ctx, "transaction", ""); char txn_ctx_name[] = { 'h', 'o', 'n', 'k', '.', 'b', 'e', 'e', 'p' }; sentry_transaction_context_set_name_n( - opaque_tx_cxt, txn_ctx_name, sizeof(txn_ctx_name)); - CHECK_STRING_PROPERTY(tx_cxt, "transaction", "honk.beep"); + opaque_tx_ctx, txn_ctx_name, sizeof(txn_ctx_name)); + CHECK_STRING_PROPERTY(tx_ctx, "transaction", "honk.beep"); - sentry_transaction_context_set_operation(opaque_tx_cxt, ""); - CHECK_STRING_PROPERTY(tx_cxt, "op", ""); + sentry_transaction_context_set_operation(opaque_tx_ctx, ""); + CHECK_STRING_PROPERTY(tx_ctx, "op", ""); char txn_ctx_op[] = { 'b', 'e', 'e', 'p', 'b', 'e', 'e', 'p' }; sentry_transaction_context_set_operation_n( - opaque_tx_cxt, txn_ctx_op, sizeof(txn_ctx_op)); - CHECK_STRING_PROPERTY(tx_cxt, "op", "beepbeep"); + opaque_tx_ctx, txn_ctx_op, sizeof(txn_ctx_op)); + CHECK_STRING_PROPERTY(tx_ctx, "op", "beepbeep"); - sentry_transaction_context_set_sampled(opaque_tx_cxt, 1); + sentry_transaction_context_set_sampled(opaque_tx_ctx, 1); TEST_CHECK( - sentry_value_is_true(sentry_value_get_by_key(tx_cxt, "sampled")) + sentry_value_is_true(sentry_value_get_by_key(tx_ctx, "sampled")) == 1); } else { - TEST_CHECK(opaque_tx_cxt != NULL); + TEST_CHECK(opaque_tx_ctx != NULL); } - sentry__transaction_context_free(opaque_tx_cxt); + sentry__transaction_context_free(opaque_tx_ctx); } static void @@ -145,15 +145,15 @@ SENTRY_TEST(transaction_name_backfill_on_finish) sentry_options_set_traces_sample_rate(options, 1.0); sentry_init(options); - sentry_transaction_context_t *tx_cxt + sentry_transaction_context_t *tx_ctx = sentry_transaction_context_new(NULL, NULL); sentry_transaction_t *tx - = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(tx_ctx, sentry_value_new_null()); sentry_uuid_t event_id = sentry_transaction_finish(tx); TEST_CHECK(!sentry_uuid_is_nil(&event_id)); - tx_cxt = sentry_transaction_context_new("", ""); - tx = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + tx_ctx = sentry_transaction_context_new("", ""); + tx = sentry_transaction_start(tx_ctx, sentry_value_new_null()); event_id = sentry_transaction_finish(tx); TEST_CHECK(!sentry_uuid_is_nil(&event_id)); @@ -197,19 +197,19 @@ run_basic_function_transport_transaction(bool timestamped) sentry_options_set_require_user_consent(options, true); sentry_init(options); - sentry_transaction_context_t *tx_cxt = sentry_transaction_context_new( + sentry_transaction_context_t *tx_ctx = sentry_transaction_context_new( "How could you", "Don't capture this."); sentry_transaction_t *tx; // TODO: `sentry_capture_event` acts as if the event was sent if user // consent was not given if (timestamped) { - tx = sentry_transaction_start_ts(tx_cxt, sentry_value_new_null(), 1); + tx = sentry_transaction_start_ts(tx_ctx, sentry_value_new_null(), 1); CHECK_STRING_PROPERTY( tx->inner, "start_timestamp", "1970-01-01T00:00:00.000001Z"); sentry_uuid_t event_id = sentry_transaction_finish_ts(tx, 2); TEST_CHECK(!sentry_uuid_is_nil(&event_id)); } else { - tx = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + tx = sentry_transaction_start(tx_ctx, sentry_value_new_null()); sentry_uuid_t event_id = sentry_transaction_finish(tx); TEST_CHECK(!sentry_uuid_is_nil(&event_id)); } @@ -217,14 +217,14 @@ run_basic_function_transport_transaction(bool timestamped) sentry_user_consent_give(); char name[] = { 'h', 'o', 'n', 'k' }; char op[] = { 'b', 'e', 'e', 'p' }; - tx_cxt + tx_ctx = sentry_transaction_context_new_n(name, sizeof(name), op, sizeof(op)); if (timestamped) { - tx = sentry_transaction_start_ts(tx_cxt, sentry_value_new_null(), 3); + tx = sentry_transaction_start_ts(tx_ctx, sentry_value_new_null(), 3); CHECK_STRING_PROPERTY( tx->inner, "start_timestamp", "1970-01-01T00:00:00.000003Z"); } else { - tx = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + tx = sentry_transaction_start(tx_ctx, sentry_value_new_null()); } CHECK_STRING_PROPERTY(tx->inner, "transaction", "honk"); CHECK_STRING_PROPERTY(tx->inner, "op", "beep"); @@ -237,18 +237,18 @@ run_basic_function_transport_transaction(bool timestamped) } sentry_user_consent_revoke(); - tx_cxt = sentry_transaction_context_new( + tx_ctx = sentry_transaction_context_new( "How could you again", "Don't capture this either."); // TODO: `sentry_capture_event` acts as if the event was sent if user // consent was not given if (timestamped) { - tx = sentry_transaction_start_ts(tx_cxt, sentry_value_new_null(), 5); + tx = sentry_transaction_start_ts(tx_ctx, sentry_value_new_null(), 5); CHECK_STRING_PROPERTY( tx->inner, "start_timestamp", "1970-01-01T00:00:00.000005Z"); sentry_uuid_t event_id = sentry_transaction_finish_ts(tx, 6); TEST_CHECK(!sentry_uuid_is_nil(&event_id)); } else { - tx = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + tx = sentry_transaction_start(tx_ctx, sentry_value_new_null()); sentry_uuid_t event_id = sentry_transaction_finish(tx); TEST_CHECK(!sentry_uuid_is_nil(&event_id)); } @@ -284,10 +284,10 @@ SENTRY_TEST(transport_sampling_transactions) uint64_t sent_transactions = 0; for (int i = 0; i < 100; i++) { - sentry_transaction_context_t *tx_cxt + sentry_transaction_context_t *tx_ctx = sentry_transaction_context_new("honk", "beep"); sentry_transaction_t *tx - = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(tx_ctx, sentry_value_new_null()); sentry_uuid_t event_id = sentry_transaction_finish(tx); if (!sentry_uuid_is_nil(&event_id)) { sent_transactions += 1; @@ -328,10 +328,10 @@ SENTRY_TEST(transactions_skip_before_send) sentry_options_set_before_send(options, before_send, &called_beforesend); sentry_init(options); - sentry_transaction_context_t *tx_cxt + sentry_transaction_context_t *tx_ctx = sentry_transaction_context_new("honk", "beep"); sentry_transaction_t *tx - = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(tx_ctx, sentry_value_new_null()); sentry_uuid_t event_id = sentry_transaction_finish(tx); TEST_CHECK(!sentry_uuid_is_nil(&event_id)); @@ -364,10 +364,10 @@ SENTRY_TEST(multiple_transactions) sentry_options_set_traces_sample_rate(options, 1.0); sentry_init(options); - sentry_transaction_context_t *tx_cxt + sentry_transaction_context_t *tx_ctx = sentry_transaction_context_new("wow!", NULL); sentry_transaction_t *tx - = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(tx_ctx, sentry_value_new_null()); sentry_set_transaction_object(tx); sentry_value_t scope_tx = sentry__scope_get_span_or_transaction(); @@ -380,12 +380,12 @@ SENTRY_TEST(multiple_transactions) // Set transaction on scope twice, back-to-back without finishing the first // one - tx_cxt = sentry_transaction_context_new("whoa!", NULL); - tx = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + tx_ctx = sentry_transaction_context_new("whoa!", NULL); + tx = sentry_transaction_start(tx_ctx, sentry_value_new_null()); sentry_set_transaction_object(tx); sentry__transaction_decref(tx); - tx_cxt = sentry_transaction_context_new("wowee!", NULL); - tx = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + tx_ctx = sentry_transaction_context_new("wowee!", NULL); + tx = sentry_transaction_start(tx_ctx, sentry_value_new_null()); sentry_set_transaction_object(tx); scope_tx = sentry__scope_get_span_or_transaction(); CHECK_STRING_PROPERTY(scope_tx, "transaction", "wowee!"); @@ -408,10 +408,10 @@ SENTRY_TEST(basic_spans) = sentry_transaction_start_child(NULL, NULL, NULL); TEST_CHECK(!parentless_child); - sentry_transaction_context_t *opaque_tx_cxt + sentry_transaction_context_t *opaque_tx_ctx = sentry_transaction_context_new("wow!", NULL); sentry_transaction_t *opaque_tx - = sentry_transaction_start(opaque_tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(opaque_tx_ctx, sentry_value_new_null()); sentry_value_t tx = opaque_tx->inner; sentry_span_t *opaque_child @@ -457,10 +457,10 @@ SENTRY_TEST(spans_on_scope) sentry_options_set_traces_sample_rate(options, 1.0); sentry_init(options); - sentry_transaction_context_t *opaque_tx_cxt + sentry_transaction_context_t *opaque_tx_ctx = sentry_transaction_context_new("wow!", NULL); sentry_transaction_t *opaque_tx - = sentry_transaction_start(opaque_tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(opaque_tx_ctx, sentry_value_new_null()); sentry_set_transaction_object(opaque_tx); sentry_span_t *opaque_child @@ -510,17 +510,17 @@ run_child_spans_test(bool timestamped) sentry_options_set_max_spans(options, 3); sentry_init(options); - sentry_transaction_context_t *opaque_tx_cxt + sentry_transaction_context_t *opaque_tx_ctx = sentry_transaction_context_new("wow!", NULL); sentry_transaction_t *opaque_tx; if (timestamped) { opaque_tx = sentry_transaction_start_ts( - opaque_tx_cxt, sentry_value_new_null(), 1); + opaque_tx_ctx, sentry_value_new_null(), 1); CHECK_STRING_PROPERTY( opaque_tx->inner, "start_timestamp", "1970-01-01T00:00:00.000001Z"); } else { opaque_tx - = sentry_transaction_start(opaque_tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(opaque_tx_ctx, sentry_value_new_null()); } sentry_value_t tx = opaque_tx->inner; @@ -601,10 +601,10 @@ SENTRY_TEST(overflow_spans) sentry_options_set_max_spans(options, 1); sentry_init(options); - sentry_transaction_context_t *opaque_tx_cxt + sentry_transaction_context_t *opaque_tx_ctx = sentry_transaction_context_new("wow!", NULL); sentry_transaction_t *opaque_tx - = sentry_transaction_start(opaque_tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(opaque_tx_ctx, sentry_value_new_null()); sentry_value_t tx = opaque_tx->inner; sentry_span_t *opaque_child @@ -651,11 +651,11 @@ SENTRY_TEST(unsampled_spans) sentry_options_set_traces_sample_rate(options, 1.0); sentry_init(options); - sentry_transaction_context_t *opaque_tx_cxt + sentry_transaction_context_t *opaque_tx_ctx = sentry_transaction_context_new("noisemakers", NULL); - sentry_transaction_context_set_sampled(opaque_tx_cxt, 0); + sentry_transaction_context_set_sampled(opaque_tx_ctx, 0); sentry_transaction_t *opaque_tx - = sentry_transaction_start(opaque_tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(opaque_tx_ctx, sentry_value_new_null()); sentry_value_t tx = opaque_tx->inner; TEST_CHECK(!sentry_value_is_true(sentry_value_get_by_key(tx, "sampled"))); @@ -744,10 +744,10 @@ SENTRY_TEST(drop_unfinished_spans) sentry_options_set_max_spans(options, 2); sentry_init(options); - sentry_transaction_context_t *opaque_tx_cxt + sentry_transaction_context_t *opaque_tx_ctx = sentry_transaction_context_new("wow!", NULL); sentry_transaction_t *opaque_tx - = sentry_transaction_start(opaque_tx_cxt, sentry_value_new_null()); + = sentry_transaction_start(opaque_tx_ctx, sentry_value_new_null()); sentry_value_t tx = opaque_tx->inner; sentry_span_t *opaque_child