Custom Instrumentation

Learn how to capture performance data on any action in your app.

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

Copied
USentrySubsystem* SentrySubsystem = GEngine->GetEngineSubsystem<USentrySubsystem>();

// Transactions can be started by providing the name and the operation
USentryTransaction* transaction = SentrySubsystem->StartTransaction(
    TEXT("transaction name"),
    TEXT("transaction operation")
);

// Transactions can have child spans (and those spans can have child spans as well)
USentrySpan* span = transaction->StartChild(
    TEXT("span name"),
    TEXT("span description")
);

// ...
// (Perform the operation represented by the span/transaction)
// ...

span->Finish();
transaction->Finish();

For example, if you want to create a transaction for a user interaction in your application:

Copied
// Let's say this method is called in a background thread when a user clicks on the checkout button.
void perform_checkout() {
    USentrySubsystem* SentrySubsystem = GEngine->GetEngineSubsystem<USentrySubsystem>();

    // This will create a new Transaction for you
    USentryTransactionContext* transactionContext = NewObject<USentryTransactionContext>();
    transactionContext->Initialize(
        TEXT("checkout"),
        TEXT("perform-checkout")
    );

    USentryTransaction* transaction =
        SentrySubsystem->StartTransactionWithContext(transactionContext);

    // Validate the cart
    USentrySpan* validationSpan = transaction->StartChild(
        TEXT("validation"),
        TEXT("validating shopping cart")
    );

    validate_shopping_cart(); // Some long process, maybe a sync http request.

    validationSpan->Finish();

    // Process the order
    SentrySpan* processSpan = transaction->StartChild(
        TEXT("process"),
        TEXT("processing shopping cart")
    );

    process_shopping_cart(); // 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 validate_shopping_cart() took and a process span that measures process_shopping_cart(). Finally, the transaction->Finish() call will finish the transaction and send it to Sentry.

Sentry errors can be linked to transactions and spans. Errors that are sent to Sentry while the transaction or span bound to the scope is running, will be linked automatically.

By default, transactions and spans are not bound to the scope. To bind them, you must explicitly pass true to the BindToScope parameter when calling USentrySubsystem::StartTransaction, USentryTransaction::StartChildSpan or USentrySpan::StartChild functions.

Copied
USentrySubsystem* SentrySubsystem = GEngine->GetEngineSubsystem<USentrySubsystem>();

// Transaction bound to the current scope
USentryTransaction* transaction = SentrySubsystem->StartTransaction(
    TEXT("transaction name"),
    TEXT("transaction operation"),
    true
);

// Child span bound to the current scope
USentrySpan* span = transaction->StartChildSpan(
    TEXT("span name"),
    TEXT("span description"),
    true
);

USentryEvent* ErrorEvent = NewObject<USentryEvent>();
ErrorEvent->Initialize();
ErrorEvent->SetLevel(ESentryLevel::Error);
ErrorEvent->SetMessage(TEXT("Error message"));

// Error event will be linked to the span
SentrySubsystem->CaptureEvent(ErrorEvent);

span->Finish();
transaction->Finish();

You can add data attributes to your transactions. This data is visible and queryable in the trace explorer in Sentry. Data attributes can be of type string, number or boolean, as well as arrays and maps of these types:

Copied
USentryTransaction* transaction = SentrySubsystem->StartTransaction(TEXT("Automation transaction"), TEXT("Automation operation"));

transaction->SetData(TEXT("key1"), {{TEXT("data_key1"), TEXT("value")}});
transaction->SetData(TEXT("key2"), {{TEXT("data_key2"), 123}});
transaction->SetData(TEXT("key3"), {{TEXT("data_key3"), 123.456f}});
transaction->SetData(TEXT("key4"), {{TEXT("data_key4"), TArray<FSentryVariant>{{123, 456}}}});
transaction->SetData(TEXT("key5"), {{TEXT("data_key5"), TMap<FString, FSentryVariant>{{TEXT("inner_key1"), 123}}}});

transaction->Finish();

You can add data attributes to your transactions. This data is visible and queryable in the trace explorer in Sentry. Data attributes can be of type string, number or boolean, as well as arrays and maps of these types:

Copied
USentryTransaction* transaction = SentrySubsystem->StartTransaction(TEXT("Automation transaction"), TEXT("Automation operation"));
USentrySpan* span = transaction->StartChildSpan(TEXT("Automation span"), TEXT("Description text"));

span->SetData(TEXT("key1"), {{TEXT("data_key1"), TEXT("value")}});
span->SetData(TEXT("key2"), {{TEXT("data_key2"), 123}});
span->SetData(TEXT("key3"), {{TEXT("data_key3"), 123.456f}});
span->SetData(TEXT("key4"), {{TEXT("data_key4"), TArray<FSentryVariant>{{123, 456}}}});
span->SetData(TEXT("key5"), {{TEXT("data_key5"), TMap<FString, FSentryVariant>{{TEXT("inner_key1"), 123}}}});

span->Finish();
transaction->Finish();

In order to use distributed tracing, follow the custom instrumentation steps.

Was this helpful?
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").