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 tracing.

To instrument certain regions of your code, you can create transactions to capture them.

The following example creates a transaction for a scope that contains an expensive operation (for example, expensive_operation), and sends the result to Sentry:

Copied
// Setup context for the full transaction
$transactionContext = \Sentry\Tracing\TransactionContext::make()
    ->setName('Example Transaction')
    ->setOp('http.server');

// Start the transaction
$transaction = \Sentry\startTransaction($transactionContext);

// Set the current transaction as the current span so we can retrieve it later
\Sentry\SentrySdk::getCurrentHub()->setSpan($transaction);

// Setup the context for the expensive operation span
$spanContext = \Sentry\Tracing\SpanContext::make()
    ->setOp('expensive_operation');

// Start the span
$span1 = $transaction->startChild($spanContext);

// Set the current span to the span we just started
\Sentry\SentrySdk::getCurrentHub()->setSpan($span1);

// Calling expensive_operation()
expensive_operation();

// Finish the span
$span1->finish();

// Set the current span back to the transaction since we just finished the previous span
\Sentry\SentrySdk::getCurrentHub()->setSpan($transaction);

// Finish the transaction, this submits the transaction and it's span to Sentry
$transaction->finish();

The next example contains the implementation of the hypothetical expensive_operation function called from the code snippet in the previous section. But this time we are using the trace function to create a new span and set it as the current span which removes a lot of boilerplate.

You can choose the values of op and description.

Copied
function expensive_operation(): void
{
    $spanContext = \Sentry\Tracing\SpanContext::make()
        ->setOp('some_operation')
        ->setDescription('This is a description');

    \Sentry\trace(function () {
        // Do the expensive operation...
    }, $spanContext);
}

You can also do this manually if you want to have more control over the span creation:

Copied
function expensive_operation(): void
{
    $parent = \Sentry\SentrySdk::getCurrentHub()->getSpan();
    $span = null;

    // Check if we have a parent span (this is the case if we started a transaction earlier)
    if ($parent !== null) {
        $context = \Sentry\Tracing\SpanContext::make()
            ->setOp('some_operation')
            ->setDescription('This is a description');
        $span = $parent->startChild($context);

        // Set the current span to the span we just started
        \Sentry\SentrySdk::getCurrentHub()->setSpan($span);
    }

    try {
        // Do the expensive operation...
    } finally {
        // We only have a span if we started a span earlier
        if ($span !== null) {
            $span->finish();

            // Restore the current span back to the parent span
            \Sentry\SentrySdk::getCurrentHub()->setSpan($parent);
        }
    }
}

This code checks for the existence of a parent span and if there is one, a new span is created and set as the current span. Then we call the expensive operation. Finally, we finish the span and restore the current span to the parent span.

In cases where you want to attach spans to an already ongoing transaction, you can use getTransaction() on the current hub. This property will return a \Sentry\Tracing\Transaction in cases where there is a transaction set; otherwise, it returns null.

Copied
$transaction = \Sentry\SentrySdk::getCurrentHub()->getTransaction();

if ($transaction !== null) {
    $context = \Sentry\Tracing\SpanContext::make();
        ->setOp('some_operation');
    $span = $transaction->startChild($context);

    // ...

    $span->finish();
}

You can also set the current transaction after you started one:

Copied
$transactionContext = \Sentry\Tracing\TransactionContext::make()
    ->setName('Example Transaction');
    ->setOp('http.server');

$transaction = \Sentry\startTransaction($transactionContext);

// A transaction is a span so we set it using `setSpan`
\Sentry\SentrySdk::getCurrentHub()->setSpan($transaction);

In cases where you want to attach spans to an already ongoing span, you can use getSpan() on the current hub. This property will return a \Sentry\Tracing\Span in cases where there is a span set; otherwise, it returns null. You can also set the current span after you started one and restore it back to the parent after your span ends.

Copied
$parentSpan = \Sentry\SentrySdk::getCurrentHub()->getSpan();

if ($parentSpan !== null) {
    $context = \Sentry\Tracing\SpanContext::make()
        ->setOp('some_operation');
    $span = $parentSpan->startChild($context);

    // Set the span we just started as the current span
    \Sentry\SentrySdk::getCurrentHub()->setSpan($span);

    // ...

    $span->finish();

    // Restore the span back to the parent span
    \Sentry\SentrySdk::getCurrentHub()->setSpan($parentSpan);
}
Help improve this content
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").