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

# Custom Instrumentation | Sentry for Flutter

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

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

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

```dart
import 'package:sentry/sentry.dart';

final transaction = Sentry.startTransaction('processOrderBatch()', 'task');

try {
  processOrderBatch();
} catch (exception) {
  transaction.throwable = exception;
  transaction.status = SpanStatus.internalError();
} finally {
  await transaction.finish();
}
```

## [Add More Spans to the Transaction](https://docs.sentry.io/platforms/dart/guides/flutter/tracing/instrumentation/custom-instrumentation.md#add-more-spans-to-the-transaction)

By default, transactions are not bound to the scope. Transaction has to be passed manually as a method parameter to enable attaching nested spans. When creating nested span, you can choose the value of `operation` and `description`.

```dart
import 'package:sentry/sentry.dart';

final transaction = Sentry.startTransaction('processOrderBatch()', 'task');

try {
  await processOrderBatch(transaction);
} catch (exception) {
  transaction.throwable = exception;
  transaction.status = SpanStatus.internalError();
} finally {
  await transaction.finish();
}

Future<void> processOrderBatch(ISentrySpan span) async {
  // span operation: task, span description: operation
  final innerSpan = span.startChild('task', description: 'operation');

  try {
    // omitted code
  } catch (exception) {
    innerSpan.throwable = exception;
    innerSpan.status = SpanStatus.notFound();
  } finally {
    await innerSpan.finish();
  }
}
```

Keep in mind that each individual span also needs to be manually finished;

Spans are sent together with their parent transaction when the transaction is finished. Make sure to call `finish()` on transaction once all the child spans have finished.

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

In cases where you want to attach Spans to an already ongoing Transaction you can use `Sentry#getSpan`. This method will return a `SentryTransaction` in case there is a running Transaction, otherwise it returns `null`.

```dart
import 'package:sentry/sentry.dart';

final span = Sentry.getSpan()?.startChild('task') ??
    Sentry.startTransaction('processOrderBatch()', 'task');

try {
  processOrderBatch();
} catch (exception) {
  span.throwable = exception;
  span.status = SpanStatus.internalError();
} finally {
  await span.finish();
}
```

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

Sentry errors can be linked with transactions and spans.

Errors reported to Sentry while transaction or span **bound to the scope** is running are linked automatically:

```dart
import 'package:sentry/sentry.dart';

final transaction = Sentry.startTransaction(
  'processOrderBatch()',
  'task',
  bindToScope: true,
);

try {
  processOrderBatch();
} catch (exception) {
  Sentry.captureException(exception);
} finally {
  await transaction.finish();
}
```

Exceptions may be thrown within spans that can finish before exception gets reported to Sentry. To attach span information to this exception, you must link it by calling the `throwable` setter method:

```dart
import 'package:sentry/sentry.dart';

final transaction = Sentry.startTransaction('processOrderBatch()', 'task');

try {
  processOrderBatch();
} catch (exception) {
  transaction.throwable = exception;
  rethrow;
} finally {
  await transaction.finish();
}
```

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

You can add data attributes to your transactions and spans. This data is visible in the trace explorer in Sentry. Data attributes can be of type `String`, `int`, `double` or `bool`, as well as (non-mixed) arrays of these types:

### [For Transactions](https://docs.sentry.io/platforms/dart/guides/flutter/tracing/instrumentation/custom-instrumentation.md#for-transactions)

```dart
final transaction = Sentry.startTransaction('my-transaction', 'http.server');
transaction.setData('data_attribute_1', 'value1');
transaction.setData('data_attribute_2', 42);
transaction.setData('data_attribute_3', true);

transaction.setData('data_attribute_4', ['value1', 'value2']);
transaction.setData('data_attribute_5', [42, 43]);
transaction.setData('data_attribute_6', [true, false]);
```

### [For Spans](https://docs.sentry.io/platforms/dart/guides/flutter/tracing/instrumentation/custom-instrumentation.md#for-spans)

```dart
final span = parent.startChild('http.client');
span.setData('data_attribute_1', 'value1');
span.setData('data_attribute_2', 42);
span.setData('data_attribute_3', true);

span.setData('data_attribute_4', ['value1', 'value2']);
span.setData('data_attribute_5', [42, 43]);
span.setData('data_attribute_6', [true, false]);
```
