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(tracing): Basic transaction context creation #619

Merged
merged 9 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from 6 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
51 changes: 51 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,57 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_traces_sample_rate(
SENTRY_EXPERIMENTAL_API double sentry_options_get_traces_sample_rate(
sentry_options_t *opts);

/* -- Performance Monitoring/Tracing APIs -- */

/**
* Constructs a new transaction context to be passed
* into `sentry_start_transaction`.
*
* See
* https://docs.sentry.io/platforms/native/enriching-events/transaction-name/
* for an explanation of a transaction's `name`, and
* https://develop.sentry.dev/sdk/performance/span-operations/ for conventions
* around an operation's name.
*
* Also see https://develop.sentry.dev/sdk/event-payloads/transaction/#anatomy
* for an explanation of `operation`, in addition to other properties and
* actions that can be performed with a transaction.
*/
SENTRY_EXPERIMENTAL_API sentry_value_t sentry_value_new_transaction_context(
const char *name, const char *operation);

/**
* Sets the name of a transaction on a `transaction_context`.
*/
SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_name(
sentry_value_t transaction_context, const char *name);

/**
* Sets the operation of a transaction on a `transaction_context`.
*
* See https://develop.sentry.dev/sdk/performance/span-operations/ for
* conventions on `operation`s.
*/
SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_operation(
sentry_value_t transaction_context, const char *operation);

/**
* Sets the sampled field on a `transaction_context`. When turned on, the
* transaction constructed from the `transaction_context` will bypass all
* sampling options and always be sent to sentry. If this is explicitly turned
* off in the `transaction_context`, the transaction will never be sent to
* sentry.
*/
SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_sampled(
sentry_value_t transaction_context, int sampled);

/**
* Removes the sampled field on a `transaction_context`. The transaction
* contructed from it will use the sampling rate as defined in `sentry_options`.
*/
SENTRY_EXPERIMENTAL_API void sentry_transaction_context_remove_sampled(
sentry_value_t transaction_context);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm strongly considering renaming all of these and stripping the _context bit of this. instead, the API would most likely look more like this:

  • sentry_value_new_transaction
  • sentry_transaction_set_name
  • sentry_transaction_set_operation
  • sentry_transaction_set_sampled
  • sentry_start_transaction
  • sentry_transaction_finish

it does mean that we paper over the difference between an inert transaction and one that is active, but you could argue that most objects are the same way (see Exceptions, Threads, Messages, etc)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is still relevant despite the outdated tag.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be ok with your newly proposed names as well

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sentry_start_transaction kind of sticks out among those name tbh. Should that be renamed to sentry_transaction_start?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me get some opinions from some of the people working on perfmon to see if they're averse to us changing the name a little in native - if they're adamant about having a function named start_transaction, perhaps we can just offer both options (sentry_start_transaction and sentry_transaction_start) and let users decide?


#ifdef __cplusplus
}
#endif
Expand Down
47 changes: 47 additions & 0 deletions src/sentry_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,53 @@ sentry_value_new_stacktrace(void **ips, size_t len)
return stacktrace;
}

sentry_value_t
sentry_value_new_transaction_context(const char *name, const char *operation)
{
sentry_value_t transaction_context = sentry_value_new_object();

sentry_transaction_context_set_name(transaction_context, name);
sentry_transaction_context_set_operation(transaction_context, operation);

return transaction_context;
}

void
sentry_transaction_context_set_name(
sentry_value_t transaction_context, const char *name)
{
sentry_value_t sv_name = sentry_value_new_string(name);
// TODO: Consider doing this checking right before sending or flushing
// the transaction.
if (sentry_value_is_null(sv_name) || sentry__string_eq(name, "")) {
sentry_value_decref(sv_name);
sv_name = sentry_value_new_string("<unlabeled transaction>");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed elsewhere, not sure if we should do validation here. But I don’t object to it either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll leave a note for the time being so the validation is still being done somewhere (in case it gets forgotten). the only other place where this validation makes sense to occur is yet to show up in a proper PR, so i think we can revisit this conversation once the implementation for that appears.

}
sentry_value_set_by_key(transaction_context, "name", sv_name);
}

void
sentry_transaction_context_set_operation(
sentry_value_t transaction_context, const char *operation)
{
sentry_value_set_by_key(
transaction_context, "op", sentry_value_new_string(operation));
}

void
sentry_transaction_context_set_sampled(
sentry_value_t transaction_context, int sampled)
{
sentry_value_set_by_key(
transaction_context, "sampled", sentry_value_new_bool(sampled));
}

void
sentry_transaction_context_remove_sampled(sentry_value_t transaction_context)
{
sentry_value_remove_by_key(transaction_context, "sampled");
}

static sentry_value_t
sentry__get_or_insert_values_list(sentry_value_t parent, const char *key)
{
Expand Down
40 changes: 40 additions & 0 deletions tests/unit/test_tracing.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,43 @@ SENTRY_TEST(basic_tracing_context)
sentry_value_decref(trace_context);
sentry_value_decref(span);
}

SENTRY_TEST(basic_transaction_context)
{
sentry_value_t tx_cxt = sentry_value_new_transaction_context(NULL, NULL);
TEST_CHECK(!sentry_value_is_null(tx_cxt));
const char *tx_name
= sentry_value_as_string(sentry_value_get_by_key(tx_cxt, "name"));
TEST_CHECK_STRING_EQUAL(tx_name, "<unlabeled transaction>");
const char *tx_op
= sentry_value_as_string(sentry_value_get_by_key(tx_cxt, "op"));
TEST_CHECK_STRING_EQUAL(tx_op, "");

sentry_value_decref(tx_cxt);
tx_cxt = sentry_value_new_transaction_context("", "");
TEST_CHECK(!sentry_value_is_null(tx_cxt));
tx_name = sentry_value_as_string(sentry_value_get_by_key(tx_cxt, "name"));
TEST_CHECK_STRING_EQUAL(tx_name, "<unlabeled transaction>");
TEST_CHECK_STRING_EQUAL(tx_op, "");

sentry_value_decref(tx_cxt);
tx_cxt = sentry_value_new_transaction_context("honk.beep", "beepbeep");
tx_name = sentry_value_as_string(sentry_value_get_by_key(tx_cxt, "name"));
TEST_CHECK_STRING_EQUAL(tx_name, "honk.beep");
tx_op = sentry_value_as_string(sentry_value_get_by_key(tx_cxt, "op"));
TEST_CHECK_STRING_EQUAL(tx_op, "beepbeep");

sentry_transaction_context_set_name(tx_cxt, "");
tx_name = sentry_value_as_string(sentry_value_get_by_key(tx_cxt, "name"));
TEST_CHECK_STRING_EQUAL(tx_name, "<unlabeled transaction>");

sentry_transaction_context_set_operation(tx_cxt, "");
tx_op = sentry_value_as_string(sentry_value_get_by_key(tx_cxt, "op"));
TEST_CHECK_STRING_EQUAL(tx_op, "");

sentry_transaction_context_set_sampled(tx_cxt, 1);
TEST_CHECK(
sentry_value_is_true(sentry_value_get_by_key(tx_cxt, "sampled")) == 1);

sentry_value_decref(tx_cxt);
}
1 change: 1 addition & 0 deletions tests/unit/tests.inc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ XX(basic_http_request_preparation_for_event)
XX(basic_http_request_preparation_for_event_with_attachment)
XX(basic_http_request_preparation_for_minidump)
XX(basic_tracing_context)
XX(basic_transaction_context)
XX(buildid_fallback)
XX(concurrent_init)
XX(count_sampled_events)
Expand Down