Custom Instrumentation
Learn how to capture performance data on any action in your app.
To capture transactions and spans customized to your organization's needs, you must first set up performance monitoring.
To instrument certain regions of your code, you can create transactions to capture them.
// Transaction can be started by providing the name and the operation
let tx_ctx = sentry::TransactionContext::new(
"transaction name",
"transaction operation",
);
let transaction = sentry::start_transaction(tx_ctx);
// Transactions can have child spans, and those spans can have child spans as well.
let span = transaction.start_child("span operation", "span description");
// ...
// Perform your operations
// ...
span.finish(); // Remember that only finished spans will be sent with the transaction
transaction.finish(); // Finishing the transaction will send it to Sentry
For example, if you want to create a transaction for a user interaction in your application:
// Let's say this method is called in a background thread when a user clicks on the checkout button of your shop
fn perform_checkout() {
// This will create a new Transaction for you
let tx_ctx = sentry::TransactionContext::new(
"checkout",
"perform-checkout",
);
let transaction = sentry::start_transaction(tx_ctx);
// Validate the cart
let validation_span = transaction.start_child(
"validation",
"validating shopping cart",
);
validate_shopping_cart() //Some long process, maybe a sync http request.
validation_span.finish();
// Process the order
let process_span = transaction.start_child(
"process",
"processing shopping cart",
)
process_shopping_cart() //Another time consuming process.
process_span.finish();
transaction.finish();
}
This example will send a transaction named checkout
to Sentry. The transaction will contain a validation
span that measures how long validate_shopping_cart()
took and a process
span that measures process_shopping_cart()
. Finally, the call to transaction.finish()
will finish the transaction and send it to Sentry.
In cases where you want to attach spans to an already ongoing transaction, you can use Scope::get_span
. This method will return a TransactionOrSpan
in case there is a running transaction or span; otherwise it returns None
.
Transactions or spans need to be manually attached to the scope using Scope::set_span
.
// Retrieve the currently running span
let parent_span = sentry::configure_scope(|scope| scope.get_span());
let span: sentry::TransactionOrSpan = match &parent_span {
Some(parent) => parent.start_child("subtask", "description").into(),
None => {
let ctx = sentry::TransactionContext::new("task", "op");
sentry::start_transaction(ctx).into()
}
};
// Set the currently running span
sentry::configure_scope(|scope| scope.set_span(Some(span)));
Special care must be taken when spawning operations as independent threads or asynchronous tasks.
In situations where the computation can run longer than the calling context, you should always start a new transaction. The SDK offers the TransactionContext::continue_from_span
method to make that more convenient.
let parent_span = sentry::configure_scope(|scope| scope.get_span());
// Create a new transaction as an independent continuation
let ctx = sentry::TransactionContext::continue_from_span(
"A long-running spawned task",
"spawned_task",
parent_span,
);
let task = async move {
let transaction = sentry::start_transaction(ctx);
// Set the newly created transaction as the *current span*
sentry::configure_scope(|scope| scope.set_span(Some(transaction.clone().into())));
// Do the actual computation
// ...
// Finish the span and send it to sentry
transaction.finish();
// The task gets a
}.bind_hub(Hub::new_from_top(Hub::current()));
task::spawn(task);
Sentry errors can be linked with transactions and spans.
Errors reported to Sentry while a transaction or span is bound to the scope are linked automatically:
let tx_ctx = sentry::TransactionContext::new(
"checkout",
"perform-checkout",
);
let transaction = sentry::start_transaction(tx_ctx);
// Bind the transaction / span to the scope:
sentry::configure_scope(|scope| scope.set_span(Some(transaction.into())));
// The error is linked to the transaction / span:
let err = "NaN".parse::<usize>().unwrap_err();
sentry::capture_error(&err);
transaction.finish();
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").