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

SentryAssetBundle returns Future by default #1462

Merged
merged 4 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

- `SentryAssetBundle` returns Future by default ([#1462](https://github.com/getsentry/sentry-dart/pull/1462))

### Features

- Support `http` >= 1.0.0 ([#1475](https://github.com/getsentry/sentry-dart/pull/1475))
Expand Down
285 changes: 153 additions & 132 deletions flutter/lib/src/sentry_asset_bundle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,27 +53,31 @@ class SentryAssetBundle implements AssetBundle {
final bool _enableStructuredDataTracing;

@override
Future<ByteData> load(String key) async {
final span = _hub.getSpan()?.startChild(
'file.read',
description: 'AssetBundle.load: ${_fileName(key)}',
);

span?.setData('file.path', key);

ByteData? data;
try {
data = await _bundle.load(key);
_setDataLength(data, span);
span?.status = SpanStatus.ok();
} catch (exception) {
span?.throwable = exception;
span?.status = SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
Future<ByteData> load(String key) {
Future<ByteData> future() async {
final span = _hub.getSpan()?.startChild(
'file.read',
description: 'AssetBundle.load: ${_fileName(key)}',
);

span?.setData('file.path', key);

ByteData? data;
try {
data = await _bundle.load(key);
_setDataLength(data, span);
span?.status = SpanStatus.ok();
} catch (exception) {
span?.throwable = exception;
span?.status = SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
}
return data;
}
return data;

return future();
}

@override
Expand All @@ -85,106 +89,119 @@ class SentryAssetBundle implements AssetBundle {
}

Future<T> _loadStructuredDataWithTracing<T>(
String key, _StringParser<T> parser) async {
final span = _hub.getSpan()?.startChild(
'file.read',
description: 'AssetBundle.loadStructuredData<$T>: ${_fileName(key)}',
String key, _StringParser<T> parser) {
Future<T> future() async {
final span = _hub.getSpan()?.startChild(
'file.read',
description:
'AssetBundle.loadStructuredData<$T>: ${_fileName(key)}',
);
span?.setData('file.path', key);

final completer = Completer<T>();

// This future is intentionally not awaited. Otherwise we deadlock with
// the completer.
// ignore: unawaited_futures
runZonedGuarded(() async {
final data = await _bundle.loadStructuredData(
key,
(value) async => await _wrapParsing(parser, value, key, span),
);
span?.setData('file.path', key);

final completer = Completer<T>();

// This future is intentionally not awaited. Otherwise we deadlock with
// the completer.
// ignore: unawaited_futures
runZonedGuarded(() async {
final data = await _bundle.loadStructuredData(
key,
(value) async => await _wrapParsing(parser, value, key, span),
);
span?.status = SpanStatus.ok();
completer.complete(data);
}, (exception, stackTrace) {
completer.completeError(exception, stackTrace);
});

T data;
try {
data = await completer.future;
_setDataLength(data, span);
span?.status = const SpanStatus.ok();
} catch (e) {
span?.throwable = e;
span?.status = const SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
span?.status = SpanStatus.ok();
completer.complete(data);
}, (exception, stackTrace) {
completer.completeError(exception, stackTrace);
});

T data;
try {
data = await completer.future;
_setDataLength(data, span);
span?.status = const SpanStatus.ok();
} catch (e) {
span?.throwable = e;
span?.status = const SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
}
return data;
}
return data;

return future();
}

Future<T> _loadStructuredBinaryDataWithTracing<T>(
String key, _ByteParser<T> parser) async {
final span = _hub.getSpan()?.startChild(
'file.read',
description:
'AssetBundle.loadStructuredBinaryData<$T>: ${_fileName(key)}',
String key, _ByteParser<T> parser) {
Future<T> future() async {
final span = _hub.getSpan()?.startChild(
'file.read',
description:
'AssetBundle.loadStructuredBinaryData<$T>: ${_fileName(key)}',
);
span?.setData('file.path', key);

final completer = Completer<T>();

// This future is intentionally not awaited. Otherwise we deadlock with
// the completer.
// ignore: unawaited_futures
runZonedGuarded(() async {
final data = await _loadStructuredBinaryDataWrapper(
key,
(value) async => await _wrapBinaryParsing(parser, value, key, span),
);
span?.setData('file.path', key);

final completer = Completer<T>();

// This future is intentionally not awaited. Otherwise we deadlock with
// the completer.
// ignore: unawaited_futures
runZonedGuarded(() async {
final data = await _loadStructuredBinaryDataWrapper(
key,
(value) async => await _wrapBinaryParsing(parser, value, key, span),
);
span?.status = SpanStatus.ok();
completer.complete(data);
}, (exception, stackTrace) {
completer.completeError(exception, stackTrace);
});

T data;
try {
data = await completer.future;
_setDataLength(data, span);
span?.status = const SpanStatus.ok();
} catch (e) {
span?.throwable = e;
span?.status = const SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
span?.status = SpanStatus.ok();
completer.complete(data);
}, (exception, stackTrace) {
completer.completeError(exception, stackTrace);
});

T data;
try {
data = await completer.future;
_setDataLength(data, span);
span?.status = const SpanStatus.ok();
} catch (e) {
span?.throwable = e;
span?.status = const SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
}
return data;
}
return data;

return future();
}

@override
Future<String> loadString(String key, {bool cache = true}) async {
final span = _hub.getSpan()?.startChild(
'file.read',
description: 'AssetBundle.loadString: ${_fileName(key)}',
);

span?.setData('file.path', key);
span?.setData('from-cache', cache);

String? data;
try {
data = await _bundle.loadString(key, cache: cache);
span?.status = SpanStatus.ok();
} catch (exception) {
span?.throwable = exception;
span?.status = SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
Future<String> loadString(String key, {bool cache = true}) {
Future<String> future() async {
final span = _hub.getSpan()?.startChild(
'file.read',
description: 'AssetBundle.loadString: ${_fileName(key)}',
);

span?.setData('file.path', key);
span?.setData('from-cache', cache);

String? data;
try {
data = await _bundle.loadString(key, cache: cache);
span?.status = SpanStatus.ok();
} catch (exception) {
span?.throwable = exception;
span?.status = SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
}
return data;
}
return data;

return future();
}

void _setDataLength(dynamic data, ISentrySpan? span) {
Expand Down Expand Up @@ -220,30 +237,34 @@ class SentryAssetBundle implements AssetBundle {
@override
// This is an override on Flutter greater than 3.1
// ignore: override_on_non_overriding_member
Future<ImmutableBuffer> loadBuffer(String key) async {
final span = _hub.getSpan()?.startChild(
'file.read',
description: 'AssetBundle.loadBuffer: ${_fileName(key)}',
);

span?.setData('file.path', key);

ImmutableBuffer data;
try {
data = await _loadBuffer(key);
_setDataLength(data, span);
span?.status = SpanStatus.ok();
} catch (exception) {
span?.throwable = exception;
span?.status = SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
Future<ImmutableBuffer> loadBuffer(String key) {
Future<ImmutableBuffer> future() async {
final span = _hub.getSpan()?.startChild(
'file.read',
description: 'AssetBundle.loadBuffer: ${_fileName(key)}',
);

span?.setData('file.path', key);

ImmutableBuffer data;
try {
data = await _loadBuffer(key);
_setDataLength(data, span);
span?.status = SpanStatus.ok();
} catch (exception) {
span?.throwable = exception;
span?.status = SpanStatus.internalError();
rethrow;
} finally {
await span?.finish();
}
return data;
}
return data;

return future();
}

Future<ImmutableBuffer> _loadBuffer(String key) async {
Future<ImmutableBuffer> _loadBuffer(String key) {
try {
// ignore: return_of_invalid_type
return (_bundle as dynamic).loadBuffer(key);
Expand Down Expand Up @@ -323,7 +344,7 @@ class SentryAssetBundle implements AssetBundle {
Future<T> loadStructuredBinaryData<T>(
String key,
FutureOr<T> Function(ByteData data) parser,
) async {
) {
if (_enableStructuredDataTracing) {
return _loadStructuredBinaryDataWithTracing<T>(key, parser);
}
Expand All @@ -335,7 +356,7 @@ class SentryAssetBundle implements AssetBundle {
Future<T> _loadStructuredBinaryDataWrapper<T>(
String key,
FutureOr<T> Function(ByteData data) parser,
) async {
) {
// The loadStructuredBinaryData method exists as of Flutter greater than 3.8
// Previous versions don't have it, but later versions do.
// We can't use `extends` in order to provide this method because this is
Expand Down