---
title: "Custom Instrumentation"
description: "Learn how to capture performance data on any action in your app."
url: https://docs.sentry.io/platforms/unreal/tracing/instrumentation/custom-instrumentation/
---

# Custom Instrumentation | Sentry for Unreal Engine

To capture transactions and spans customized to your organization's needs, you must first [set up tracing.](https://docs.sentry.io/platforms/unreal/tracing.md)

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

```cpp
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->StartChildSpan(
    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:

```cpp
// 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->StartChildSpan(
        TEXT("validation"),
        TEXT("validating shopping cart")
    );

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

    validationSpan->Finish();

    // Process the order
    USentrySpan* processSpan = transaction->StartChildSpan(
        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.

## [Connect Errors With Spans](https://docs.sentry.io/platforms/unreal/tracing/instrumentation/custom-instrumentation.md#connect-errors-with-spans)

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.

```cpp
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();
```

## [Improving Data on Transactions and Spans](https://docs.sentry.io/platforms/unreal/tracing/instrumentation/custom-instrumentation.md#improving-data-on-transactions-and-spans)

### [Adding Data Attributes to Transactions](https://docs.sentry.io/platforms/unreal/tracing/instrumentation/custom-instrumentation.md#adding-data-attributes-to-transactions)

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:

```cpp
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();
```

### [Adding Data Attributes to Spans](https://docs.sentry.io/platforms/unreal/tracing/instrumentation/custom-instrumentation.md#adding-data-attributes-to-spans)

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:

```cpp
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();
```

## [Distributed Tracing](https://docs.sentry.io/platforms/unreal/tracing/instrumentation/custom-instrumentation.md#distributed-tracing)

In order to use distributed tracing, follow the [custom instrumentation](https://docs.sentry.io/platforms/unreal/tracing/trace-propagation/custom-instrumentation.md) steps.
