sqflite Database Instrumentation
Learn more about the Sentry sqflite Database Instrumentation for the Flutter SDK.
References to "transactions" on this page apply to the default transaction mode. In stream mode, this integration creates service spans instead, and Sentry sends them as they finish. See Streamed Spans for more information.
This feature is currently in Beta. Beta features are still in progress and may have bugs. We recognize the irony.
(New in version 7.2.0)
The sentry_sqflite package provides sqflite support for database instrumentation and allows you to track the performance of your queries.
- The created spans attach to the active span. In transaction mode, that's the transaction bound to the scope; in stream mode, it's the span started with
Sentry.startSpan(). If no span is active, the sqflite span won't be sent to Sentry. - The spans'
operationare eitherdb,db.sql.execute,db.sql.queryordb.sql.transaction. Itsdescriptionis the SQL statement using placeholders instead of its values due to the possibility of containing PII.
Before starting, ensure:
Add the sentry_sqflite dependency to install the sqflite database instrumentation.
pubspec.yamldependencies:
sentry_flutter: ^9.30.0
sentry_sqflite: ^9.30.0
sqflite: ^2.0.0
dependencies:
sentry_flutter: ^9.30.0
sentry_sqflite: ^9.30.0
sqflite: ^2.0.0
There are multiple ways to configure the sqflite database instrumentation:
By using the global databaseFactory, (which is used by the openDatabase method). With this approach, every call to openDatabase will be instrumented, including from other packages:
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
databaseFactory = SentrySqfliteDatabaseFactory();
final database = await openDatabase('path/to/db');
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
databaseFactory = SentrySqfliteDatabaseFactory();
final database = await openDatabase('path/to/db');
If you're using the FFI factories, you can instrument the SentrySqfliteDatabaseFactory with its factory:
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
databaseFactory = SentrySqfliteDatabaseFactory(databaseFactory: databaseFactoryFfi);
final database = await openDatabase('path/to/db');
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
databaseFactory = SentrySqfliteDatabaseFactory(databaseFactory: databaseFactoryFfi);
final database = await openDatabase('path/to/db');
Use the openDatabaseWithSentry wrapper - with this approach only the database opened with this method will be instrumented:
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
final database = await openDatabaseWithSentry('path/to/db');
// or final database = await openReadOnlyDatabaseWithSentry('path/to/db');
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
final database = await openDatabaseWithSentry('path/to/db');
// or final database = await openReadOnlyDatabaseWithSentry('path/to/db');
Use the SentryDatabase wrapper which can be used to instrument any Database instance:
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
final database = await openDatabase('path/to/db');
final sentryDatabase = SentryDatabase(database);
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
final database = await openDatabase('path/to/db');
final sentryDatabase = SentryDatabase(database);
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
Future<void> sqfliteTest() async {
final tr = Sentry.startTransaction(
'sqfliteTest',
'db',
bindToScope: true,
);
// You can also use the other configuration methods
final db = await openDatabaseWithSentry(inMemoryDatabasePath);
await db.execute('''CREATE TABLE Product (id INTEGER PRIMARY KEY,title TEXT)''');
final dbTitles = <String>[];
for (int i = 1; i <= 20; i++) {
final title = 'Product $i';
dbTitles.add(title);
await db.insert('Product', <String, Object?>{'title': title});
}
await db.query('Product');
await db.transaction((txn) async {
await txn
.insert('Product', <String, Object?>{'title': 'Product Another one'});
await txn.delete('Product',
where: 'title = ?', whereArgs: ['Product Another one']);
});
await db.delete('Product', where: 'title = ?', whereArgs: ['Product 1']);
await db.close();
await tr.finish(status: const SpanStatus.ok());
}
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
Future<void> sqfliteTest() async {
final tr = Sentry.startTransaction(
'sqfliteTest',
'db',
bindToScope: true,
);
// You can also use the other configuration methods
final db = await openDatabaseWithSentry(inMemoryDatabasePath);
await db.execute('''CREATE TABLE Product (id INTEGER PRIMARY KEY,title TEXT)''');
final dbTitles = <String>[];
for (int i = 1; i <= 20; i++) {
final title = 'Product $i';
dbTitles.add(title);
await db.insert('Product', <String, Object?>{'title': title});
}
await db.query('Product');
await db.transaction((txn) async {
await txn
.insert('Product', <String, Object?>{'title': 'Product Another one'});
await txn.delete('Product',
where: 'title = ?', whereArgs: ['Product Another one']);
});
await db.delete('Product', where: 'title = ?', whereArgs: ['Product 1']);
await db.close();
await tr.finish(status: const SpanStatus.ok());
}
import 'package:sentry_sqflite/sentry_sqflite.dart';
import 'package:sqflite/sqflite.dart';
Future<void> sqfliteTest() async {
await Sentry.startSpan('sqfliteTest', (span) async {
// You can also use the other configuration methods
final db = await openDatabaseWithSentry(inMemoryDatabasePath);
await db.execute('''CREATE TABLE Product (id INTEGER PRIMARY KEY,title TEXT)''');
final dbTitles = <String>[];
for (int i = 1; i <= 20; i++) {
final title = 'Product $i';
dbTitles.add(title);
await db.insert('Product', <String, Object?>{'title': title});
}
await db.query('Product');
await db.transaction((txn) async {
await txn
.insert('Product', <String, Object?>{'title': 'Product Another one'});
await txn.delete('Product',
where: 'title = ?', whereArgs: ['Product Another one']);
});
await db.delete('Product', where: 'title = ?', whereArgs: ['Product 1']);
await db.close();
}, parentSpan: null);
}
To view the recorded transaction, log into sentry.io and open your project (via main navigation menu Dashboards). Clicking View Transactions (in Quick Links section) will open a page with transactions, where you can select the just recorded transaction with the name sqfliteTest.
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").