Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[starfish] add attributes to db spans data #1629

Merged
merged 13 commits into from
Sep 8, 2023
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Enhancements

- Add db.system and db.name attributes to db spans data ([#1629](https://github.com/getsentry/sentry-dart/pull/1629))

### Features

- Tracing without performance ([#1621](https://github.com/getsentry/sentry-dart/pull/1621))
Expand Down
9 changes: 8 additions & 1 deletion sqflite/lib/src/sentry_batch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:sqflite/sqflite.dart';
import 'package:sqflite_common/src/sql_builder.dart';

import 'sentry_database.dart';
import 'utils/sentry_database_span_attributes.dart';

/// A [Batch] wrapper that adds Sentry support.
///
Expand All @@ -21,6 +22,7 @@ import 'sentry_database.dart';
class SentryBatch implements Batch {
final Batch _batch;
final Hub _hub;
final String? _dbName;

// we don't clear the buffer because SqfliteBatch don't either
final _buffer = StringBuffer();
Expand All @@ -36,7 +38,9 @@ class SentryBatch implements Batch {
SentryBatch(
this._batch, {
@internal Hub? hub,
}) : _hub = hub ?? HubAdapter();
@internal String? dbName,
}) : _hub = hub ?? HubAdapter(),
_dbName = dbName;

@override
Future<List<Object?>> apply({bool? noResult, bool? continueOnError}) {
Expand All @@ -47,8 +51,10 @@ class SentryBatch implements Batch {
SentryDatabase.dbOp,
description: _buffer.toString().trim(),
);

// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteBatch;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _batch.apply(
Expand Down Expand Up @@ -86,6 +92,7 @@ class SentryBatch implements Batch {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteBatch;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _batch.commit(
Expand Down
37 changes: 33 additions & 4 deletions sqflite/lib/src/sentry_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:sqflite/sqflite.dart';
import 'sentry_database_executor.dart';
import 'sentry_sqflite_transaction.dart';
import 'version.dart';
import 'utils/sentry_database_span_attributes.dart';

/// A [Database] wrapper that adds Sentry support.
///
Expand All @@ -31,6 +32,18 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database {
static const dbSqlQueryOp = 'db.sql.query';

static const _dbSqlOp = 'db.sql.transaction';
@internal
// ignore: public_member_api_docs
static const dbSystemKey = 'db.system';
@internal
// ignore: public_member_api_docs
static const dbSystem = 'sqlite';
@internal
// ignore: public_member_api_docs
static const dbNameKey = 'db.name';
@internal
// ignore: public_member_api_docs
String? dbName;

/// ```dart
/// import 'package:sqflite/sqflite.dart';
Expand All @@ -43,13 +56,27 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database {
this._database, {
@internal Hub? hub,
}) : _hub = hub ?? HubAdapter(),
super(_database, hub: hub) {
dbName = _basenameWithoutExtension(_database.path),
super(_database,
hub: hub, dbName: _basenameWithoutExtension(_database.path)) {
// ignore: invalid_use_of_internal_member
final options = _hub.options;
options.sdk.addIntegration('SentrySqfliteTracing');
options.sdk.addPackage(packageName, sdkVersion);
}

/// Gets the part of path after the last separator, and without any trailing file extension.
static String _basenameWithoutExtension(String filePath) {
final int lastIndex = filePath.lastIndexOf('/');
final int dotIndex = filePath.lastIndexOf('.');

if (dotIndex == -1 || (lastIndex != -1 && dotIndex < lastIndex)) {
return filePath;
}

return filePath.substring(lastIndex + 1, dotIndex);
}

// TODO: check if perf is enabled

@override
Expand All @@ -66,6 +93,7 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database {
try {
await _database.close();

dbName = null;
span?.status = SpanStatus.ok();
} catch (exception) {
span?.throwable = exception;
Expand Down Expand Up @@ -113,12 +141,13 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabase;
setDatabaseAttributeData(span, dbName);

Future<T> newAction(Transaction txn) async {
final executor =
SentryDatabaseExecutor(txn, parentSpan: span, hub: _hub);
final executor = SentryDatabaseExecutor(txn,
parentSpan: span, hub: _hub, dbName: dbName);
final sentrySqfliteTransaction =
SentrySqfliteTransaction(executor, hub: _hub);
SentrySqfliteTransaction(executor, hub: _hub, dbName: dbName);

return await action(sentrySqfliteTransaction);
}
Expand Down
20 changes: 18 additions & 2 deletions sqflite/lib/src/sentry_database_executor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,28 @@ import 'package:sqflite_common/src/sql_builder.dart';

import 'sentry_batch.dart';
import 'sentry_database.dart';
import 'utils/sentry_database_span_attributes.dart';

@internal
// ignore: public_member_api_docs
class SentryDatabaseExecutor implements DatabaseExecutor {
final DatabaseExecutor _executor;
final ISentrySpan? _parentSpan;
final String? _dbName;

// ignore: public_member_api_docs
SentryDatabaseExecutor(
this._executor, {
ISentrySpan? parentSpan,
@internal Hub? hub,
@internal String? dbName,
}) : _parentSpan = parentSpan,
_hub = hub ?? HubAdapter();
_hub = hub ?? HubAdapter(),
_dbName = dbName;
final Hub _hub;

@override
Batch batch() => SentryBatch(_executor.batch(), hub: _hub);
Batch batch() => SentryBatch(_executor.batch(), hub: _hub, dbName: _dbName);

@override
Database get database => _executor.database;
Expand All @@ -41,6 +45,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result =
Expand Down Expand Up @@ -68,8 +73,10 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
SentryDatabase.dbSqlExecuteOp,
description: sql,
);
span?.setData(SentryDatabase.dbSystemKey, SentryDatabase.dbSystem);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
await _executor.execute(sql, arguments);
Expand Down Expand Up @@ -107,6 +114,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.insert(
Expand Down Expand Up @@ -163,6 +171,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.query(
Expand Down Expand Up @@ -226,6 +235,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.queryCursor(
Expand Down Expand Up @@ -266,6 +276,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.rawDelete(sql, arguments);
Expand Down Expand Up @@ -294,6 +305,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.rawInsert(sql, arguments);
Expand Down Expand Up @@ -325,6 +337,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.rawQuery(sql, arguments);
Expand Down Expand Up @@ -357,6 +370,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.rawQueryCursor(
Expand Down Expand Up @@ -389,6 +403,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.rawUpdate(sql, arguments);
Expand Down Expand Up @@ -430,6 +445,7 @@ class SentryDatabaseExecutor implements DatabaseExecutor {
);
// ignore: invalid_use_of_internal_member
span?.origin = SentryTraceOrigins.autoDbSqfliteDatabaseExecutor;
setDatabaseAttributeData(span, _dbName);

try {
final result = await _executor.update(
Expand Down
7 changes: 5 additions & 2 deletions sqflite/lib/src/sentry_sqflite_transaction.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@ import 'sentry_batch.dart';
class SentrySqfliteTransaction extends Transaction implements DatabaseExecutor {
final DatabaseExecutor _executor;
final Hub _hub;
final String? _dbName;

// ignore: public_member_api_docs
@internal
SentrySqfliteTransaction(
this._executor, {
@internal Hub? hub,
}) : _hub = hub ?? HubAdapter();
@internal String? dbName,
}) : _hub = hub ?? HubAdapter(),
_dbName = dbName;

@override
Batch batch() => SentryBatch(_executor.batch(), hub: _hub);
Batch batch() => SentryBatch(_executor.batch(), hub: _hub, dbName: _dbName);

@override
Database get database => _executor.database;
Expand Down
12 changes: 12 additions & 0 deletions sqflite/lib/src/utils/sentry_database_span_attributes.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:sentry/sentry.dart';

import '../../sentry_sqflite.dart';

/// Sets the database attributes on the [span].
/// It contains the database system and the database name.
void setDatabaseAttributeData(ISentrySpan? span, String? dbName) {
span?.setData(SentryDatabase.dbSystemKey, SentryDatabase.dbSystem);
if (dbName != null) {
span?.setData(SentryDatabase.dbNameKey, dbName);
}
}
3 changes: 2 additions & 1 deletion sqflite/test/mocks/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ ISentrySpan startTransactionShim(
DatabaseExecutor,
],
customMocks: [
MockSpec<Hub>(fallbackGenerators: {#startTransaction: startTransactionShim})
MockSpec<Hub>(
fallbackGenerators: {#startTransaction: startTransactionShim}),
],
)
void main() {}
33 changes: 33 additions & 0 deletions sqflite/test/sentry_batch_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,39 @@ SELECT * FROM Product''';
await db.close();
});

test('apply creates db span with dbSystem and dbName attributes', () async {
final db = await fixture.getDatabase();
final batch = db.batch();

batch.insert('Product', <String, Object?>{'title': 'Product 1'});

await batch.apply();

final span = fixture.tracer.children.last;
expect(span.data[SentryDatabase.dbSystemKey], SentryDatabase.dbSystem);
expect(
span.data[SentryDatabase.dbNameKey], (db as SentryDatabase).dbName);

await db.close();
});

test('commit creates db span with dbSystem and dbName attributes',
() async {
final db = await fixture.getDatabase();
final batch = db.batch();

batch.insert('Product', <String, Object?>{'title': 'Product 1'});

await batch.commit();

final span = fixture.tracer.children.last;
expect(span.data[SentryDatabase.dbSystemKey], SentryDatabase.dbSystem);
expect(
span.data[SentryDatabase.dbNameKey], (db as SentryDatabase).dbName);

await db.close();
});

tearDown(() {
databaseFactory = sqfliteDatabaseFactoryDefault;
});
Expand Down
Loading