Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add traces_sampler #1108

Merged
merged 35 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
60dc201
add traces_sampler option
JoshuaMoelans Dec 20, 2024
dd25b29
update CHANGELOG.md
JoshuaMoelans Dec 20, 2024
9dc332f
introduced `sentry_traces_sampler_function` typedef
JoshuaMoelans Dec 20, 2024
26ff58a
added sampling context
JoshuaMoelans Dec 23, 2024
cc77b52
format
JoshuaMoelans Dec 23, 2024
7344f8a
eof newlines
JoshuaMoelans Dec 24, 2024
78f01c9
feat: pass sampling_context into sampling decision
JoshuaMoelans Jan 3, 2025
49c60eb
remove unnecessary commented include
JoshuaMoelans Jan 3, 2025
2fe7646
add memory freeing/incref-decref
JoshuaMoelans Jan 3, 2025
e08bc8e
change custom sampling context type to sentry_value_t
JoshuaMoelans Jan 7, 2025
2be1836
add decref
JoshuaMoelans Jan 7, 2025
76ca4d2
removed unneeded creation function
JoshuaMoelans Jan 7, 2025
c35fa07
format
JoshuaMoelans Jan 7, 2025
1279675
set codeql runner to ubuntu-22.04
JoshuaMoelans Jan 7, 2025
4e4aa0a
take ownership of custom_sampling_ctx
JoshuaMoelans Jan 9, 2025
372e887
add parent sampling decision
JoshuaMoelans Jan 9, 2025
17177ec
add traces_sampler and parent sampling decision tests
JoshuaMoelans Jan 9, 2025
d43df63
decref
JoshuaMoelans Jan 9, 2025
87efced
change callback arg from struct to parameter list
JoshuaMoelans Jan 9, 2025
f2fe073
format
JoshuaMoelans Jan 9, 2025
a9e2057
mark unused parameters
JoshuaMoelans Jan 10, 2025
a79245c
format
JoshuaMoelans Jan 10, 2025
d172a80
cleanup test + docs
JoshuaMoelans Jan 10, 2025
77e4b23
Merge branch 'master' into joshua/feat/tracesSampler_support
supervacuus Jan 10, 2025
39d9aa3
apply PR feedback
JoshuaMoelans Jan 13, 2025
bfaefe8
format
JoshuaMoelans Jan 13, 2025
e159e12
cleanup example
JoshuaMoelans Jan 13, 2025
a9d7221
add getters for transaction_ctx name + operation
JoshuaMoelans Jan 13, 2025
4610f33
remove (void) on transaction_ctx in example.c
JoshuaMoelans Jan 13, 2025
370b162
add transaction_ctx getter tests
JoshuaMoelans Jan 13, 2025
eb3f9c5
dont expose sampling_context_s in sentry.h
JoshuaMoelans Jan 14, 2025
2936acc
change bool to int
JoshuaMoelans Jan 14, 2025
2175251
cleanup example.c
JoshuaMoelans Jan 14, 2025
72baf78
refactor tx_cxt to tx_ctx convention
JoshuaMoelans Jan 14, 2025
e1d191e
change sampled_int init
JoshuaMoelans Jan 14, 2025
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 @@ -5,6 +5,7 @@
**Features**:

- 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
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
JoshuaMoelans marked this conversation as resolved.
Show resolved Hide resolved
- `traces-sampler`: Installs a traces sampler callback function when used alongside `capture-transaction`.

Only on Windows using crashpad with its WER handler module:

Expand Down
36 changes: 35 additions & 1 deletion examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,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 bool *parent_sampled)
JoshuaMoelans marked this conversation as resolved.
Show resolved Hide resolved
{
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)
{
Expand Down Expand Up @@ -232,6 +258,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");
}
Expand Down Expand Up @@ -403,8 +433,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"));
Expand Down
48 changes: 37 additions & 11 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ extern "C" {

#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
JoshuaMoelans marked this conversation as resolved.
Show resolved Hide resolved
#include <stddef.h>

/* context type dependencies */
Expand Down Expand Up @@ -1533,6 +1534,27 @@ 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 struct sentry_sampling_context_s sentry_sampling_context_t;
JoshuaMoelans marked this conversation as resolved.
Show resolved Hide resolved
typedef double (*sentry_traces_sampler_function)(
const sentry_transaction_context_t *transaction_ctx,
sentry_value_t custom_sampling_ctx, const bool *parent_sampled);
JoshuaMoelans marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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 bool 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

/**
Expand Down Expand Up @@ -1590,15 +1612,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.
*
Expand Down Expand Up @@ -1652,6 +1665,11 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_name(
sentry_transaction_context_t *tx_cxt, 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);
/**
* 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
Expand All @@ -1668,6 +1686,11 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_operation(
SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_operation_n(
sentry_transaction_context_t *tx_cxt, 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
Expand Down Expand Up @@ -1735,14 +1758,17 @@ 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
* mention what kind of expectations they carry if they need to mutate or access
* 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_cxt, sentry_value_t custom_sampling_ctx);
JoshuaMoelans marked this conversation as resolved.
Show resolved Hide resolved
/**
* Also starts a transaction like the regular `sentry_transaction_start`
* function, but has an additional timestamp parameter to let the user provide
Expand All @@ -1751,7 +1777,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_cxt, sentry_value_t custom_sampling_ctx,
uint64_t timestamp);

/**
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 33 additions & 17 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "sentry_os.h"
#include "sentry_path.h"
#include "sentry_random.h"
#include "sentry_sampling_context.h"
#include "sentry_scope.h"
#include "sentry_session.h"
#include "sentry_string.h"
Expand Down Expand Up @@ -448,18 +449,35 @@ sentry__capture_event(sentry_value_t event)
}

bool
sentry__should_send_transaction(sentry_value_t tx_cxt)
sentry__should_send_transaction(
sentry_value_t tx_cxt, sentry_sampling_context_t *sampling_ctx)
{
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);
}
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;

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);
JoshuaMoelans marked this conversation as resolved.
Show resolved Hide resolved
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);
}
}
JoshuaMoelans marked this conversation as resolved.
Show resolved Hide resolved
}
if (sampling_ctx->parent_sampled != NULL) {
sampling_ctx->parent_sampled = NULL;
}
return send;
}
Expand Down Expand Up @@ -840,21 +858,17 @@ 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_cxt,
sentry_value_t custom_sampling_ctx)
{
return sentry_transaction_start_ts(
opaque_tx_cxt, sampling_ctx, sentry__usec_time());
opaque_tx_cxt, 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_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) {
return NULL;
}
Expand All @@ -875,10 +889,12 @@ sentry_transaction_start_ts(sentry_transaction_context_t *opaque_tx_cxt,
sentry_value_remove_by_key(tx, "timestamp");

sentry__value_merge_objects(tx, tx_cxt);

bool should_sample = sentry__should_send_transaction(tx_cxt);
sentry_sampling_context_t sampling_ctx
= { opaque_tx_cxt, custom_sampling_ctx, NULL };
bool should_sample = sentry__should_send_transaction(tx_cxt, &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(
Expand Down
3 changes: 2 additions & 1 deletion src/sentry_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,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_cxt, sentry_sampling_context_t *sampling_ctx);
#endif

#endif
7 changes: 7 additions & 0 deletions src/sentry_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions src/sentry_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions src/sentry_sampling_context.h
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions src/sentry_tracing.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ sentry_transaction_context_set_name_n(
}
}

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)
Expand All @@ -133,6 +140,13 @@ sentry_transaction_context_set_operation_n(sentry_transaction_context_t *tx_cxt,
}
}

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)
Expand Down
Loading
Loading