Custom Instrumentation
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.
import Sentry;
// Transaction can be started by providing the name and the operation
let transaction = SentrySDK.startTransaction(
name: "transaction-name",
operation: "transaction-operation"
)
// Transactions can have child spans, and those spans can have child spans as well.
let span = transaction.startChild(operation: "child-operation")
// ...
// 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
func performCheckout()
{
// This will create a new Transaction for you
let transaction = SentrySDK.startTransaction(
name: "checkout",
operation: "perform-checkout"
)
// Validate the cart
let validationSpan = transaction.startChild(
operation: "validation",
description: "validating shopping cart"
)
validateShoppingCart() //Some long process, maybe a sync http request.
validationSpan.finish()
// Process the order
let processSpan = transaction.startChild(
operation: "process",
description: "processing shopping cart"
)
processShoppingCart() //Another time consuming process.
processSpan.finish();
transaction.finish();
}
This example will send a transaction named checkout
to Sentry. The transaction will contain a validation
span that measures how long validateShoppingCart()
took and a process
span that measures processShoppingCart()
. Finally, the call to transaction.finish()
will finish the transaction and send it to Sentry.
Our SDK can bind a transaction to the scope making it accessible to every method running within this scope by calling SentrySDK#startTransaction
method with bindToScope
parameter to true
.
bindToScope
additionally ensures that your new transaction replaces any one that may be already started. This is useful if you want custom instrumentation to co-exist with auto-instrumented transactions.
In cases where you want to attach Spans to an already ongoing Transaction you can use SentrySDK.span
. This method will return a SpanProtocol
in case there is a running Transaction or a Span
in case there is already a running Span, otherwise it returns nil
.
import Sentry
let transaction = SentrySDK.startTransaction(
name: "processOrderBatch",
operation: "task",
bindToScope: true
)
processOrderBatch()
transaction.finish()
func processOrderBatch() {
var span = SentrySDK.span
if span == nil {
span = SentrySDK.startTransaction(name: "processOrderBatch", operation: "task")
}
var innerSpan = span.startChild(operation: "subtask")
// omitted code
innerSpan.finish()
}
Sentry errors can be linked to transactions and spans. Errors that are sent to Sentry while the transaction or span bound to the scope method is running, will be linked automatically:
import Sentry
let transaction = SentrySDK.startTransaction(name: "Transaction Name", operation: "operation", bindToScope: true)
do {
try processItem()
transaction.finish()
} catch {
SentrySDK.capture(error: error)
transaction.finish(status: .internalError)
}
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").