Skip to main content

Instrumentation

Description — Instrumenting Couchbase Lite for Debugging, Crash Reporting and Performance Profiling

The execution of certain operations can be traced through the tracing API. This is useful for debugging and performance profiling.

CBL Dart has builtin trace points at which flow control is given to the currently installed TracingDelegate.

Included in this package is the DevToolsTracing delegate, which records timeline events that can be later visualized through the Dart DevTools Performance Page.

You can install a delegate by calling TracingDelegate.install:

await TracingDelegate.install(DevToolsTracing());

Sentry

The Sentry integration provided by cbl_sentry installs a DevToolsTracing to transparently record breadcrumbs and transaction spans.

Features

  • Record log messages as Sentry breadcrumbs
  • Record CBL Dart API usage as Sentry breadcrumbs
  • Record CBL Dart operations as Sentry transaction spans

Limitations

Sentry currently does not support binding transaction spans to zones. This means there can only be one global transaction span that integrations can transparently access. To support more advanced use cases, this package provides a mechanism to bind transaction spans to zones. This mechanism will be removed if and when Sentry supports this natively.

Getting started

  1. Make sure your app is setup for using Couchbase Lite.

  2. Add the cbl_sentry package as a dependency:

    flutter pub add cbl_sentry
  3. Add the CouchbaseLiteIntegration when configuring Sentry:

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

    void main() {
    Sentry.init(
    (options) {
    options
    ..dsn = ...
    // While testing your Sentry configuration, make sure that all traces are sampled.
    ..tracesSampleRate = 1
    // Add the CBL Dart integration.
    ..addIntegration(CouchbaseLiteIntegration());
    },
    appRunner: () async {
    runApp(MyApp());
    }
    );
    }

    To find out about configurable options, see the documentation of CouchbaseLiteIntegration.

    caution

    Make sure you don't install a TracingDelegate when using the CouchbaseLiteIntegration. The integration has to be able to install a TracingDelegate itself.

Performance tracing

This integration only records transaction spans when a transaction has been started and a child span of the transaction is available in the environment.

To find a span, the integration uses cblSentrySpan. This is a getter that returns either a span that has been bound to the current zone or as a fallback the result of Sentry.getSpan. To bind a span to a zone use runWithCblSentrySpan.

The following code snippet shows functions that are useful to trace the performance of operations in an app:

Future<T> runAppTransaction<T>(String name, Future<T> Function() fn) =>
_runAppSpan(Sentry.startTransaction(name, 'task'), fn);

Future<T> runAppOperation<T>(String name, Future<T> Function() fn) =>
_runAppSpan(cblSentrySpan!.startChild(name), fn);

Future<T> _runAppSpan<T>(ISentrySpan span,Future<T> Function() fn) async {
try {
return await runWithCblSentrySpan(span, fn);
// ignore: avoid_catches_without_on_clauses
} catch (e) {
span
..throwable = e
..status = const SpanStatus.internalError();
rethrow;
} finally {
span.status ??= const SpanStatus.ok();
await span.finish();
}
}

A app operation like the one below is traced as a transaction span, with CBL Dart operations as child spans:

Future<void> queryDatabase() => runAppOperation('queryDatabase', () async {
final query = await db.createQuery(
'SELECT * FROM example WHERE age >= 28 OR name LIKE "A%"',
);
final resultSet = await query.execute();
final results = await resultSet
.asStream()
.map((result) => result.toPlainMap())
.toList();

prettyPrintJson(results);
});

Sentry Trace Example