# Custom Instrumentation | Sentry for Unity

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

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

```csharp
// Transaction can be started by providing, at minimum, the name and the operation
var transaction = SentrySdk.StartTransaction(
  "test-transaction-name",
  "test-transaction-operation"
);

// Transactions can have child spans (and those spans can have child spans as well)
var span = transaction.StartChild("test-child-operation");

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

span.Finish(); // Mark the span as finished
transaction.Finish(); // Mark the transaction as finished and send it to Sentry
```

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

```csharp
// Let's say this method is invoked when a user clicks on the checkout button of your shop
public async Task PerformCheckoutAsync()
{
  // This will create a new Transaction for you
  var transaction = SentrySdk.StartTransaction(
      "checkout", // name
      "perform-checkout" // operation
  );

  // Set transaction on scope to associate with errors and get included span instrumentation
  // If there's currently an unfinished transaction, it may be dropped
  SentrySdk.ConfigureScope(scope => scope.Transaction = transaction);

  // Validate the cart
  var validationSpan = transaction.StartChild(
      "validation", // operation
      "validating shopping cart" // description
  );

  await ValidateShoppingCartAsync();

  validationSpan.Finish();

  // Process the order
  var processSpan = transaction.StartChild(
      "process", // operation
      "processing shopping cart" // description
  )

  await ProcessShoppingCartAsync();

  processSpan.Finish();

  transaction.Finish();
}
```

This example will send a transaction `checkout` to Sentry. The transaction will contain a `validation` span that measures how long `ValidateShoppingCartAsync` took and a `process` span that measures `ProcessShoppingCartAsync`. Finally, the call to `transaction.Finish()` will finish the transaction and send it to Sentry.

## [Retrieve a Transaction](https://docs.sentry.io/platforms/unity/tracing/instrumentation/custom-instrumentation.md#retrieve-a-transaction)

In cases where you want to attach Spans to an already ongoing Transaction you can use `SentrySdk.GetSpan()`. If there is a running Transaction or Span currently on the scope, this method will return a `SentryTransaction` or `Span`; otherwise, it returns `null`.

```csharp
var span = SentrySdk.GetSpan();

if (span == null)
{
    span = SentrySdk.StartTransaction("task", "op");
}
else
{
    span = span.StartChild("subtask");
}
```

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

### [Adding Data Attributes to Transactions](https://docs.sentry.io/platforms/unity/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 of these types:

```csharp
var transaction = SentrySdk.StartTransaction("ProcessOrderBatch()", "task");
SentrySdk.ConfigureScope(scope => scope.Transaction = transaction);
transaction.SetData("my-data-attribute-1", "value1");
transaction.SetData("my-data-attribute-2", 42);
transaction.SetData("my-data-attribute-3", true);

transaction.SetData("my-data-attribute-4", new[] {"value1", "value2", "value3"});
transaction.SetData("my-data-attribute-5", new[] {42, 43, 44});
transaction.SetData("my-data-attribute-6", new[] {true, false, true});
```

### [Adding Data Attributes to Spans](https://docs.sentry.io/platforms/unity/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 of these types:

```csharp
var span = parent.StartChild("task", "operation");
span.SetData("my-data-attribute-1", "value1");
span.SetData("my-data-attribute-2", 42);
span.SetData("my-data-attribute-3", true);

span.SetData("my-data-attribute-4", new[] {"value1", "value2", "value3"});
span.SetData("my-data-attribute-5", new[] {42, 43, 44});
span.SetData("my-data-attribute-6", new[] {true, false, true});
```

### [Adding Attributes to all Spans and Transactions](https://docs.sentry.io/platforms/unity/tracing/instrumentation/custom-instrumentation.md#adding-attributes-to-all-spans-and-transactions)

To add an attribute to all spans and transactions, use the `SetBeforeSendTransaction` callback:

```csharp
options =>
{
    options.SetBeforeSendTransaction(transaction =>
    {
        // Set the attribute on the root span (transaction's trace context)
        transaction.Contexts.Trace.SetData("myAttribute", "myValue");

        // And on all child spans
        foreach (var span in transaction.Spans)
        {
            span.SetData("myAttribute", "myValue");
        }

        return transaction;
    });
};
```
