From 85df9db26cd3c51148dfd6e2d6fd98c7ed71e0fa Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 2 Dec 2022 11:00:04 +0100 Subject: [PATCH 01/23] Tracing for File IO integration --- .craft.yml | 2 + .gitignore | 1 + CHANGELOG.md | 4 + README.md | 3 +- file/CHANGELOG.md | 1 + file/LICENSE | 21 ++ file/README.md | 29 +++ file/analysis_options.yaml | 24 ++ file/example/example.dart | 16 ++ file/lib/sentry_file.dart | 1 + file/lib/src/sentry_file.dart | 312 +++++++++++++++++++++++++ file/lib/src/version.dart | 2 + file/new.txt | 0 file/pubspec.yaml | 20 ++ file/pubspec_overrides.yaml | 3 + file/test.txt | 0 file/test/mock_sentry_client.dart | 27 +++ file/test/no_such_method_provider.dart | 7 + file/test/sentry_file_test.dart | 73 ++++++ file/test/version_test.dart | 17 ++ file/test_resources/sentry.png | Bin 0 -> 3535 bytes file/test_resources/testfile.txt | 1 + 22 files changed, 563 insertions(+), 1 deletion(-) create mode 120000 file/CHANGELOG.md create mode 100644 file/LICENSE create mode 100644 file/README.md create mode 100644 file/analysis_options.yaml create mode 100644 file/example/example.dart create mode 100644 file/lib/sentry_file.dart create mode 100644 file/lib/src/sentry_file.dart create mode 100644 file/lib/src/version.dart create mode 100644 file/new.txt create mode 100644 file/pubspec.yaml create mode 100644 file/pubspec_overrides.yaml create mode 100644 file/test.txt create mode 100644 file/test/mock_sentry_client.dart create mode 100644 file/test/no_such_method_provider.dart create mode 100644 file/test/sentry_file_test.dart create mode 100644 file/test/version_test.dart create mode 100644 file/test_resources/sentry.png create mode 100644 file/test_resources/testfile.txt diff --git a/.craft.yml b/.craft.yml index 70e6fb387..181e929f4 100644 --- a/.craft.yml +++ b/.craft.yml @@ -9,6 +9,7 @@ targets: flutter: logging: dio: + file: - name: github - name: registry sdks: @@ -16,3 +17,4 @@ targets: pub:sentry_flutter: pub:sentry_logging: pub:sentry_dio: + #pub:sentry_dio: diff --git a/.gitignore b/.gitignore index b2807fa8e..742ddcded 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ build/ dart/coverage/* logging/coverage/* dio/coverage/* +file/coverage/* pubspec.lock Podfile.lock flutter/coverage/* diff --git a/CHANGELOG.md b/CHANGELOG.md index b996ec1a7..f221e1538 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Tracing for File IO integration ([#1152](https://github.com/getsentry/sentry-dart/pull/1152)) + ### Dependencies - Bump Cocoa SDK from v7.31.2 to v7.31.3 ([#1157](https://github.com/getsentry/sentry-dart/pull/1157)) diff --git a/README.md b/README.md index cb5d8f991..86a986819 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,11 @@ Sentry SDK for Dart and Flutter | sentry_flutter | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-flutter/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-flutter) | [![pub package](https://img.shields.io/pub/v/sentry_flutter.svg)](https://pub.dev/packages/sentry_flutter) | [![likes](https://img.shields.io/pub/likes/sentry_flutter?logo=dart)](https://pub.dev/packages/sentry_flutter/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_flutter?logo=dart)](https://pub.dev/packages/sentry_flutter/score) | [![pub points](https://img.shields.io/pub/points/sentry_flutter?logo=dart)](https://pub.dev/packages/sentry_flutter/score) | sentry_logging | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-logging/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Alogging) | [![pub package](https://img.shields.io/pub/v/sentry_logging.svg)](https://pub.dev/packages/sentry_logging) | [![likes](https://img.shields.io/pub/likes/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) | [![pub points](https://img.shields.io/pub/points/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) | sentry_dio | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-dio/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-dio) | [![pub package](https://img.shields.io/pub/v/sentry_dio.svg)](https://pub.dev/packages/sentry_dio) | [![likes](https://img.shields.io/pub/likes/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) | [![pub points](https://img.shields.io/pub/points/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) +| sentry_file | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry_file/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry_file) | [![pub package](https://img.shields.io/pub/v/sentry_file.svg)](https://pub.dev/packages/sentry_file) | [![likes](https://img.shields.io/pub/likes/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) | [![pub points](https://img.shields.io/pub/points/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) ##### Usage -For detailed usage, check out the inner [dart](https://github.com/getsentry/sentry-dart/tree/main/dart), [flutter](https://github.com/getsentry/sentry-dart/tree/main/flutter), [logging](https://github.com/getsentry/sentry-dart/tree/main/logging) and [dio](https://github.com/getsentry/sentry-dart/tree/main/dio) `README's` or our `Resources` section below. +For detailed usage, check out the inner [dart](https://github.com/getsentry/sentry-dart/tree/main/dart), [flutter](https://github.com/getsentry/sentry-dart/tree/main/flutter), [logging](https://github.com/getsentry/sentry-dart/tree/main/logging), [dio](https://github.com/getsentry/sentry-dart/tree/main/dio) and [file](https://github.com/getsentry/sentry-dart/tree/main/file) `README's` or our `Resources` section below. #### Blog posts diff --git a/file/CHANGELOG.md b/file/CHANGELOG.md new file mode 120000 index 000000000..04c99a55c --- /dev/null +++ b/file/CHANGELOG.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/file/LICENSE b/file/LICENSE new file mode 100644 index 000000000..2a6964d84 --- /dev/null +++ b/file/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Sentry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/file/README.md b/file/README.md new file mode 100644 index 000000000..7eca7b509 --- /dev/null +++ b/file/README.md @@ -0,0 +1,29 @@ +

+ + + +
+

+ +Sentry integration for `dart.io.File` +=========== + +| package | build | pub | likes | popularity | pub points | +| ------- | ------- | ------- | ------- | ------- | ------- | +| sentry_file | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-file/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-file) | [![pub package](https://img.shields.io/pub/v/sentry_file.svg)](https://pub.dev/packages/sentry_file) | [![likes](https://img.shields.io/pub/likes/sentry_file)](https://pub.dev/packages/sentry_file/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_file)](https://pub.dev/packages/sentry_file/score) | [![pub points](https://img.shields.io/pub/points/sentry_file)](https://pub.dev/packages/sentry_file/score) + +#### Usage + +- Sign up for a Sentry.io account and get a DSN at https://sentry.io. + +- Follow the installing instructions on [pub.dev](https://pub.dev/packages/sentry/install). + +- Initialize the Sentry SDK using the DSN issued by Sentry.io. + +#### Resources + +* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dart/) +* [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) +* [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +* [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) +* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) diff --git a/file/analysis_options.yaml b/file/analysis_options.yaml new file mode 100644 index 000000000..c5924fcb2 --- /dev/null +++ b/file/analysis_options.yaml @@ -0,0 +1,24 @@ +include: package:lints/recommended.yaml + +analyzer: + exclude: + - example/** # the example has its own 'analysis_options.yaml' + errors: + # treat missing required parameters as a warning (not a hint) + missing_required_param: error + # treat missing returns as a warning (not a hint) + missing_return: error + # allow having TODOs in the code + todo: ignore + # allow self-reference to deprecated members (we do this because otherwise we have + # to annotate every member in every test, assert, etc, when we deprecate something) + deprecated_member_use_from_same_package: warning + +linter: + rules: + prefer_relative_imports: true + unnecessary_brace_in_string_interps: true + prefer_function_declarations_over_variables: false + no_leading_underscores_for_local_identifiers: false + avoid_renaming_method_parameters: false + unawaited_futures: true diff --git a/file/example/example.dart b/file/example/example.dart new file mode 100644 index 000000000..03477bfcf --- /dev/null +++ b/file/example/example.dart @@ -0,0 +1,16 @@ +import 'package:sentry/sentry.dart'; + +Future main() async { + // ATTENTION: Change the DSN below with your own to see the events in Sentry. Get one at sentry.io + const dsn = + 'https://e85b375ffb9f43cf8bdf9787768149e0@o447951.ingest.sentry.io/5428562'; + + await Sentry.init( + (options) { + options.dsn = dsn; + }, + appRunner: runApp, // Init your App. + ); +} + +Future runApp() async {} diff --git a/file/lib/sentry_file.dart b/file/lib/sentry_file.dart new file mode 100644 index 000000000..35ceec610 --- /dev/null +++ b/file/lib/sentry_file.dart @@ -0,0 +1 @@ +export 'src/sentry_file.dart'; diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart new file mode 100644 index 000000000..568cc74d8 --- /dev/null +++ b/file/lib/src/sentry_file.dart @@ -0,0 +1,312 @@ +// Adapted from https://github.com/ueman/sentry-dart-tools/blob/8e41418c0f2c62dc88292cf32a4f22e79112b744/sentry_plus/lib/src/file/sentry_file.dart + +// ignore_for_file: invalid_use_of_internal_member + +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; +import 'package:meta/meta.dart'; +import 'package:sentry/sentry.dart'; + +typedef Callback = T Function(); + +class SentryFile implements File { + SentryFile( + this._file, { + @internal Hub? hub, + }) : _hub = hub ?? HubAdapter(); + + final File _file; + final Hub _hub; + + @override + Future copy(String newPath) { + return _wrap(_file.copy(newPath), 'file.copy'); + } + + @override + File copySync(String newPath) { + return _wrapSync(() => _file.copySync(newPath), 'file.copy'); + } + + @override + Future create({bool recursive = false}) { + return _wrap( + _file.create(recursive: recursive), + 'file.create', + ); + } + + @override + void createSync({bool recursive = false, bool exclusive = false}) { + return _wrapSync( + () => _file.createSync(recursive: recursive), + 'file.create', + ); + } + + @override + Future delete({bool recursive = false}) { + return _wrap(_file.delete(recursive: recursive), 'file.delete'); + } + + @override + void deleteSync({bool recursive = false}) { + _wrapSync(() => _file.deleteSync(recursive: recursive), 'file.delete'); + } + + @override + Future open({FileMode mode = FileMode.read}) { + return _wrap(_file.open(mode: mode), 'file.open'); + } + + @override + Stream> openRead([int? start, int? end]) { + return _file.openRead(start, end); + } + + @override + RandomAccessFile openSync({FileMode mode = FileMode.read}) { + return _file.openSync(mode: mode); + } + + @override + IOSink openWrite({FileMode mode = FileMode.write, Encoding encoding = utf8}) { + return _file.openWrite(mode: mode, encoding: encoding); + } + + @override + Future readAsBytes() { + return _wrap(_file.readAsBytes(), 'file.read'); + } + + @override + Uint8List readAsBytesSync() { + return _wrapSync(() => _file.readAsBytesSync(), 'file.read'); + } + + @override + Future> readAsLines({Encoding encoding = utf8}) { + return _wrap(_file.readAsLines(encoding: encoding), 'file.read'); + } + + @override + List readAsLinesSync({Encoding encoding = utf8}) { + return _wrapSync( + () => _file.readAsLinesSync(encoding: encoding), + 'file.read', + ); + } + + @override + Future readAsString({Encoding encoding = utf8}) { + return _wrap(_file.readAsString(encoding: encoding), 'file.read'); + } + + @override + String readAsStringSync({Encoding encoding = utf8}) { + return _wrapSync( + () => _file.readAsStringSync(encoding: encoding), + 'file.read', + ); + } + + @override + Future rename(String newPath) { + return _wrap(_file.rename(newPath), 'file.rename'); + } + + @override + File renameSync(String newPath) { + return _wrapSync(() => _file.renameSync(newPath), 'file.rename'); + } + + @override + Future writeAsBytes( + List bytes, { + FileMode mode = FileMode.write, + bool flush = false, + }) { + return _wrap( + _file.writeAsBytes(bytes, mode: mode, flush: flush), + 'file.write', + ); + } + + @override + void writeAsBytesSync( + List bytes, { + FileMode mode = FileMode.write, + bool flush = false, + }) { + _wrapSync( + () => _file.writeAsBytesSync(bytes, mode: mode, flush: flush), + 'file.write', + ); + } + + @override + Future writeAsString( + String contents, { + FileMode mode = FileMode.write, + Encoding encoding = utf8, + bool flush = false, + }) { + return _wrap( + _file.writeAsString( + contents, + mode: mode, + encoding: encoding, + flush: flush, + ), + 'file.write', + ); + } + + @override + void writeAsStringSync( + String contents, { + FileMode mode = FileMode.write, + Encoding encoding = utf8, + bool flush = false, + }) { + _wrapSync( + () => _file.writeAsStringSync( + contents, + mode: mode, + encoding: encoding, + flush: flush, + ), + 'file.write', + ); + } + + Future _wrap(Future future, String operation) async { + final span = _hub.getSpan()?.startChild(operation, description: _file.path); + span?.setData('async-io', true); + if (_hub.options.sendDefaultPii) { + // if (_hub.options.sendDefaultPii || _hub.options.platformChecker.isMobile) { + span?.setData('file.path', path); + } + T data; + try { + data = await future; + if (data is List) { + span?.setData('file.size', data.length); + } + span?.status = SpanStatus.ok(); + } catch (exception) { + span?.throwable = exception; + span?.status = SpanStatus.internalError(); + rethrow; + } finally { + await span?.finish(); + } + return data; + } + + T _wrapSync(Callback callback, String operation) { + final span = _hub.getSpan()?.startChild(operation, description: _file.path); + span?.setData('async-io', false); + + if (_hub.options.sendDefaultPii) { + // if (_hub.options.sendDefaultPii || _hub.options.platformChecker.isMobile) { + span?.setData('file.path', path); + } + T data; + try { + data = callback(); + if (data is List) { + span?.setData('file.size', data.length); + } + span?.status = SpanStatus.ok(); + } catch (exception) { + span?.throwable = exception; + span?.status = SpanStatus.internalError(); + rethrow; + } finally { + span?.finish(); + } + return data; + } + + // coverage:ignore-start + + @override + Stream watch({ + int events = FileSystemEvent.all, + bool recursive = false, + }) => + _file.watch(events: events, recursive: recursive); + + @override + Future resolveSymbolicLinks() => _file.resolveSymbolicLinks(); + + @override + String resolveSymbolicLinksSync() => _file.resolveSymbolicLinksSync(); + + @override + Future setLastAccessed(DateTime time) => _file.setLastAccessed(time); + + @override + void setLastAccessedSync(DateTime time) => _file.setLastAccessedSync(time); + + @override + Future setLastModified(DateTime time) => _file.setLastModified(time); + + @override + void setLastModifiedSync(DateTime time) => _file.setLastAccessedSync(time); + + @override + Directory get parent => _file.parent; + + @override + String get path => _file.path; + + @override + File get absolute => _file.absolute; + + @override + Future exists() => _file.exists(); + + @override + bool existsSync() => _file.existsSync(); + + @override + bool get isAbsolute => _file.isAbsolute; + + @override + Future lastAccessed() => _file.lastAccessed(); + + @override + DateTime lastAccessedSync() => _file.lastAccessedSync(); + + @override + Future lastModified() => _file.lastModified(); + + @override + DateTime lastModifiedSync() => _file.lastModifiedSync(); + + @override + Future length() => _file.length(); + + @override + int lengthSync() => _file.lengthSync(); + + @override + Future stat() => _file.stat(); + + @override + FileStat statSync() => _file.statSync(); + + @override + Uri get uri => _file.uri; + + // coverage:ignore-end +} + +// extension on PlatformChecker { +// bool get isMobile { +// return platform.isIOS || platform.isAndroid; +// } +// } diff --git a/file/lib/src/version.dart b/file/lib/src/version.dart new file mode 100644 index 000000000..e8297f135 --- /dev/null +++ b/file/lib/src/version.dart @@ -0,0 +1,2 @@ +/// The SDK version reported to Sentry.io in the submitted events. +const String sdkVersion = '6.17.0'; diff --git a/file/new.txt b/file/new.txt new file mode 100644 index 000000000..e69de29bb diff --git a/file/pubspec.yaml b/file/pubspec.yaml new file mode 100644 index 000000000..fe353892c --- /dev/null +++ b/file/pubspec.yaml @@ -0,0 +1,20 @@ +name: sentry_file +description: An integration which adds support for performance tracing for dart.io.File. +version: 6.17.0 +homepage: https://docs.sentry.io/platforms/dart/ +repository: https://github.com/getsentry/sentry-dart +issue_tracker: https://github.com/getsentry/sentry-dart/issues + +environment: + # <2.19 because of https://github.com/dart-lang/sdk/issues/49647 breaking change + sdk: '>=2.12.0 <2.19.0' + +dependencies: + sentry: 6.17.0 + meta: ^1.3.0 + +dev_dependencies: + lints: ^2.0.0 + test: ^1.21.1 + coverage: ^1.3.0 + mockito: ^5.1.0 diff --git a/file/pubspec_overrides.yaml b/file/pubspec_overrides.yaml new file mode 100644 index 000000000..16e71d16f --- /dev/null +++ b/file/pubspec_overrides.yaml @@ -0,0 +1,3 @@ +dependency_overrides: + sentry: + path: ../dart diff --git a/file/test.txt b/file/test.txt new file mode 100644 index 000000000..e69de29bb diff --git a/file/test/mock_sentry_client.dart b/file/test/mock_sentry_client.dart new file mode 100644 index 000000000..c68fde9b4 --- /dev/null +++ b/file/test/mock_sentry_client.dart @@ -0,0 +1,27 @@ +import 'package:sentry/sentry.dart'; + +import 'no_such_method_provider.dart'; + +final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; + +class MockSentryClient with NoSuchMethodProvider implements SentryClient { + List captureTransactionCalls = []; + + @override + Future captureTransaction( + SentryTransaction transaction, { + Scope? scope, + SentryTraceContextHeader? traceContext, + }) async { + captureTransactionCalls + .add(CaptureTransactionCall(transaction, traceContext)); + return transaction.eventId; + } +} + +class CaptureTransactionCall { + final SentryTransaction transaction; + final SentryTraceContextHeader? traceContext; + + CaptureTransactionCall(this.transaction, this.traceContext); +} diff --git a/file/test/no_such_method_provider.dart b/file/test/no_such_method_provider.dart new file mode 100644 index 000000000..64253e965 --- /dev/null +++ b/file/test/no_such_method_provider.dart @@ -0,0 +1,7 @@ +mixin NoSuchMethodProvider { + @override + void noSuchMethod(Invocation invocation) { + 'Method ${invocation.memberName} was called ' + 'with arguments ${invocation.positionalArguments}'; + } +} diff --git a/file/test/sentry_file_test.dart b/file/test/sentry_file_test.dart new file mode 100644 index 000000000..103780640 --- /dev/null +++ b/file/test/sentry_file_test.dart @@ -0,0 +1,73 @@ +@TestOn('vm') + +import 'dart:io'; + +import 'package:sentry/sentry.dart'; +import 'package:sentry_file/sentry_file.dart'; +import 'package:test/test.dart'; + +import 'mock_sentry_client.dart'; + +typedef Callback = T Function(); + +void main() { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('uri returns test', () { + final file = File('test.txt'); + final sut = fixture.getSut(file, tracesSampleRate: 1.0); + + expect(sut.uri.toFilePath(), 'test.txt'); + }); + + test('copy wraps with a trace', () async { + final file = File('test.txt'); + await file.create(recursive: true); + expect(await file.exists(), true); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + var newFile = await sut.copy('new.txt'); + + await tr.finish(); + + final exists = await newFile.exists(); + expect(exists, true); + + expect(file.uri.toFilePath(), isNot(newFile.uri.toFilePath())); + + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; + + expect(span.context.operation, 'file.copy'); + }); +} + +class Fixture { + final client = MockSentryClient(); + final options = SentryOptions(dsn: fakeDsn); + late Hub hub; + + SentryFile getSut( + File file, { + bool sendDefaultPii = false, + double? tracesSampleRate, + }) { + options.sendDefaultPii = sendDefaultPii; + options.tracesSampleRate = tracesSampleRate; + + hub = Hub(options); + hub.bindClient(client); + return SentryFile(file, hub: hub); + } +} diff --git a/file/test/version_test.dart b/file/test/version_test.dart new file mode 100644 index 000000000..8bba9116b --- /dev/null +++ b/file/test/version_test.dart @@ -0,0 +1,17 @@ +@TestOn('vm') + +import 'dart:io'; + +import 'package:sentry/src/version.dart'; +import 'package:test/test.dart'; +import 'package:yaml/yaml.dart' as yaml; + +void main() { + group('sdkVersion', () { + test('matches that of pubspec.yaml', () { + final dynamic pubspec = + yaml.loadYaml(File('pubspec.yaml').readAsStringSync()); + expect(sdkVersion, pubspec['version']); + }); + }); +} diff --git a/file/test_resources/sentry.png b/file/test_resources/sentry.png new file mode 100644 index 0000000000000000000000000000000000000000..2225be472dcbe274d67c07a4995ac46fbe620ff5 GIT binary patch literal 3535 zcmV;=4KVVFP)E`C4~jn{Grh46iQo`OCw@?C$3Byx(+ds>k_Fwu9+EO}D68T-{~@x93f_syZCs$o?&H zI%>LQ72!Ac?=K#%n{Hbrcv3s~7yp5k+WTg8@W0SSWea}dYtt<(iPKOAv)iVdSPsv@ z4rbY9(~T^HV@C(G?6~P>mOyxoE-`JonZ@ystAmGZPtTk^ylc9lMe*I)!7TgIbW;n$ z-N7vDHQm-ixWvB9U+J$GO*gg(kSTr)j*foO2Z!j{{G<-9KKU0u`POi23*ee&YW*2~ zba;$0fnI!He|80*%^PiP0Z=C*m__@4;&I>&=fuHJVAluO+&3M0NQ4Yy=NZanX5)xTLihI_2=-+TO+M40Ah+i z;wh4-o*QUw5xha$rSyx8aTs|iG9pj#+yy-M6P{}wkSSP}d7n%l5iLLg2fp1LAZ#0S%Xl_Wczk~054}7ON{DIbn%4QCV zF{rWO%-Iya)z+jbR0U-x!Ee#hc6_Y~kkPQ1;sa!!PLsE`0EVPXxV}k~*v6_inhKv$ zq?)M~CQT{Th_NMyIs8U@lBVQ5XOp;synFbG zMO!3rt$ZzR3aECYElE=;VjFJN1@r%HI5~7r0?jriUS6Xbj;Dkz z_v6{LHh*`MGx3Rx(T=3)$UNMXxkX;ekmqTe?#4BV*IV#y#@-yh+M1;4Z;F6E;S&gn zFbHIZJ+q#vNu#_^BDeGUAQ-w>fGa|wmxZUALa7+H?1$TIZ-2xB^>(V0hHO8 z)9CP|DN}xyzS%MOiibwlaF~8_k=m9trM={DE2+ybZIi%>);JG12@jhtr=0M-z0wePSU#xjF4{)i{ca`WwIh^lL^ag#(^Z-5>`y5 zxZzgFKs=MM%*K+?Hn3`7IG8d^^lD9-YP`LNZ#s?lc^_Nu0y0LbGMn7j!)&6P$74De zWjiW0CQbbpTg~+rGu=EH{}#(^k|a&Hhuy8N2r>MXkZNbjN^Y@m*6 zMnyS%Awii9sR~nFE}W@d?4bZ>aU5E>>dR~(m#`R)^Wo9Md*dRD?%Ut7Z(S0(nn(>5iP9)udusGb*ZqG3Z~c1qJA;zdQ zX-ZpXQx|zc?Oj1#dB}>^vZK&zR%OzZmenWe4pn=j+VtppU@FY4u*`;reCJ%6nx0Vg zO`;4-3{A`!B(Lo@M@>&?nOiy=YZhE2O`4Lq+}GDNkLOm~EQaku3=<|z@wbIp&{Rg1 znQ5I`u`rd{RCG6ibA4#Us2Oz<-^>#v$r!_3N~c9v8kN(?S&TtLQc2R3>@*Xd(nT%* z-iK#R+E0`;MJG}*(@Gb$R?xb(YzN*=P`)sevUn=hDtl3DHmEkHqMamZN-XfEyGwWr zvU*gKc9x}2V3|!x2^<%OMO);K>FX4{K~vGDHBz!L6B99}$IHcDian(PH0Okz{8C9% zj*RU0-{4D0v|tW)mRb6QCr!&Rh9<9BI#3T)Uxk|KT$rg8R-80tyRpR7Q1ei8(5w?U zduH&ChM{m_CZ0lCH%@)-dwFYJE9ShGO!7#qGcrUjb4w zX?m=e-K*3u-4(@m16M4N0nMQurORy8mAcT}LfF4b!=(ZfD3z_6G2Wr_hPpoFpeR)r zuxA6dF-_7`wW%7HL&{2-MCn)rLL#gJEq~JV8mnP4-9?pVT`{MU^&bLlA*Z>5!pwmd z5^Gyg4hd@xpq+-w@)NxRWUO>i8$HP~%7rs>UxoZIOqy0uW;0UG_-b;HOw92(OXD~X zrFc`_O)w&fI8)!fA-P%cP9@)l>;@)Oswm7Hu({Ffsf-l4<6$~8FD#^ zPxzelYl7!vP)7Q?`OR1BcIwDR6~!!AYCe9BsMj^yNqb(D2QB~3vtF~kJ= zX~kO>KRm;5T>7S-W4{r%*`N$*jA9Ot^Cp+}0GH`l%(bVM1hcsODBbXA2|{E~6_OSq zJWsZ0flCB+Crv4VY{y%ml_+AhaI3jGLl|hi9DWP#SAbBu$mV@AHoS9WBhV(v)$BSF z>%7pNG~ZAm2WTZq^dfc`FMnaoeRUSlbh*^)=zo1Be< zFzNj3;@6y|he5``D~dhG8NgCI<6Dj<^Zm!13TW`8DOJh(%$N+&*!>n`_=4V&SQFk; zc!4q-O2;|xNr5OEn=a31qM;U?<<7Q{1pc|#N$zmobpt0$d0`3t79BjX>fIO85T9@4 z5)zi&g;ZWSUU&yMJJP0m+i{dbFV>@2?zIcjP;+`oEay99MBzKSPyQHh!6qRfqM%Va zr^pv_cChWj?E8qm;zwngc&Q2aj8`4E}%mzyc!h!1YN{b z#}co9C8~%#LoD41^s0rPf^ojMhc4=P8u(_v$Y+f#X^{@T8D7Ig<5Fvcm= zdBm2bNMnqFrQEL=H{^Q{xulv6q+y?fKNp+r?~6g=l_i8tbPV@dO|7_Mh~6wfhm4^3B7Ww7|`nz>+fN5CLyK)cWe0K zxDQ;KH{cfruD^o+2^~{^53kI_O@;A9t48XS@RE(7uP?iMlFz0n|`@kb%?jA0k z59_Q!QTUu{A8^IHd${r{%ooEH1B&qldx+taw}2-mm2)C0h4uGv%eAW7v1vyScdT&e^@WjWMGyDBXutL@ z7H#OE;885aD~jfOID_!!*gn=Ag~ogMtQ?Ya-GuBx@*bW~PXTvJ!D4ZCY1O6PKTjv~ z7ssX6Hj?vUIrK+^I&|pJp+krC_#dbpto#olR51Vm002ov JPDHLkV1hwO&o}@8 literal 0 HcmV?d00001 diff --git a/file/test_resources/testfile.txt b/file/test_resources/testfile.txt new file mode 100644 index 000000000..96c906756 --- /dev/null +++ b/file/test_resources/testfile.txt @@ -0,0 +1 @@ +foo bar \ No newline at end of file From 0e48d001ac060fe64555595f331c21e88c713b71 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 2 Dec 2022 11:19:58 +0100 Subject: [PATCH 02/23] add file workflow --- .github/workflows/file.yml | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/workflows/file.yml diff --git a/.github/workflows/file.yml b/.github/workflows/file.yml new file mode 100644 index 000000000..148cd3cf9 --- /dev/null +++ b/.github/workflows/file.yml @@ -0,0 +1,66 @@ +name: sentry-file +on: + push: + branches: + - main + - release/** + pull_request: + paths-ignore: + - 'logging/**' + - 'flutter/**' + - 'dio/**' + +jobs: + cancel-previous-workflow: + runs-on: ubuntu-latest + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # pin@0.11.0 + with: + access_token: ${{ github.token }} + + build: + name: Build ${{matrix.sdk}} on ${{matrix.os}} + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + defaults: + run: + shell: bash + working-directory: ./file + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + sdk: [stable, beta] + exclude: + - os: macos-latest + sdk: beta + steps: + - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d # pin@v1 + with: + sdk: ${{ matrix.sdk }} + - uses: actions/checkout@v3 + # coverage with 'chrome' platform hangs the build + - name: Test (VM and browser) + run: | + dart pub get + dart test -p chrome --test-randomize-ordering-seed=random --chain-stack-traces + dart test -p vm --coverage=coverage --test-randomize-ordering-seed=random --chain-stack-traces + dart pub run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib + + - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # pin@v3 + if: runner.os == 'Linux' && matrix.sdk == 'stable' + with: + name: sentry_file + files: ./file/coverage/lcov.info + + - uses: VeryGoodOpenSource/very_good_coverage@84e5b54ab888644554e5573dca87d7f76dec9fb3 # pin@v2.0.0 + if: runner.os == 'Linux' && matrix.sdk == 'stable' + with: + path: './file/coverage/lcov.info' + min_coverage: 81 + + analyze: + uses: ./.github/workflows/analyze.yml + with: + package: file From 0f74b5bad6f4afb1602a952accaf5a7599b6d180 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 2 Dec 2022 11:20:22 +0100 Subject: [PATCH 03/23] fix pr id --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f221e1538..c704a9180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Features -- Tracing for File IO integration ([#1152](https://github.com/getsentry/sentry-dart/pull/1152)) +- Tracing for File IO integration ([#1160](https://github.com/getsentry/sentry-dart/pull/1160)) ### Dependencies From 2a999cddfb5f51f79b99324e7ec370fe15ce6ff8 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 2 Dec 2022 12:09:05 +0100 Subject: [PATCH 04/23] copy tests --- file/lib/src/sentry_file.dart | 45 ++++++++++------ file/test/sentry_file_test.dart | 91 +++++++++++++++++++++++---------- 2 files changed, 93 insertions(+), 43 deletions(-) diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index 568cc74d8..d3d7e460c 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -33,7 +33,7 @@ class SentryFile implements File { Future create({bool recursive = false}) { return _wrap( _file.create(recursive: recursive), - 'file.create', + 'file.write', ); } @@ -41,7 +41,7 @@ class SentryFile implements File { void createSync({bool recursive = false, bool exclusive = false}) { return _wrapSync( () => _file.createSync(recursive: recursive), - 'file.create', + 'file.write', ); } @@ -60,6 +60,8 @@ class SentryFile implements File { return _wrap(_file.open(mode: mode), 'file.open'); } + // coverage:ignore-start + @override Stream> openRead([int? start, int? end]) { return _file.openRead(start, end); @@ -75,6 +77,8 @@ class SentryFile implements File { return _file.openWrite(mode: mode, encoding: encoding); } + // coverage:ignore-end + @override Future readAsBytes() { return _wrap(_file.readAsBytes(), 'file.read'); @@ -181,18 +185,29 @@ class SentryFile implements File { ); } + String _getDesc() { + return uri.pathSegments.isNotEmpty ? uri.pathSegments.last : path; + } + Future _wrap(Future future, String operation) async { - final span = _hub.getSpan()?.startChild(operation, description: _file.path); - span?.setData('async-io', true); + final desc = _getDesc(); + + final currentSpan = _hub.getSpan(); + final span = currentSpan?.startChild(operation, description: desc); + + span?.setData('file.async', true); if (_hub.options.sendDefaultPii) { - // if (_hub.options.sendDefaultPii || _hub.options.platformChecker.isMobile) { - span?.setData('file.path', path); + span?.setData('file.path', absolute.path); } T data; try { data = await future; if (data is List) { span?.setData('file.size', data.length); + } else if (data is File) { + span?.setData('file.size', await data.length()); + // TODO: if its a copy, we need the new path here too or not? + // TODO: append size in bytes or human readable size } span?.status = SpanStatus.ok(); } catch (exception) { @@ -206,18 +221,22 @@ class SentryFile implements File { } T _wrapSync(Callback callback, String operation) { - final span = _hub.getSpan()?.startChild(operation, description: _file.path); - span?.setData('async-io', false); + final desc = _getDesc(); + + final currentSpan = _hub.getSpan(); + final span = currentSpan?.startChild(operation, description: desc); + span?.setData('file.async', false); if (_hub.options.sendDefaultPii) { - // if (_hub.options.sendDefaultPii || _hub.options.platformChecker.isMobile) { - span?.setData('file.path', path); + span?.setData('file.path', absolute.path); } T data; try { data = callback(); if (data is List) { span?.setData('file.size', data.length); + } else if (data is File) { + span?.setData('file.size', data.lengthSync()); } span?.status = SpanStatus.ok(); } catch (exception) { @@ -304,9 +323,3 @@ class SentryFile implements File { // coverage:ignore-end } - -// extension on PlatformChecker { -// bool get isMobile { -// return platform.isIOS || platform.isAndroid; -// } -// } diff --git a/file/test/sentry_file_test.dart b/file/test/sentry_file_test.dart index 103780640..39bd016ad 100644 --- a/file/test/sentry_file_test.dart +++ b/file/test/sentry_file_test.dart @@ -11,45 +11,82 @@ import 'mock_sentry_client.dart'; typedef Callback = T Function(); void main() { - late Fixture fixture; + group('$SentryFile copy', () { + late Fixture fixture; - setUp(() { - fixture = Fixture(); - }); + setUp(() { + fixture = Fixture(); + }); - test('uri returns test', () { - final file = File('test.txt'); - final sut = fixture.getSut(file, tracesSampleRate: 1.0); + test('copy async', () async { + final file = File('test_resources/testfile.txt'); - expect(sut.uri.toFilePath(), 'test.txt'); - }); + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + final newFile = await sut.copy('test_resources/testfile_copy.txt'); + + await tr.finish(); + + final exists = await newFile.exists(); + expect(exists, true); + + expect(sut.uri.toFilePath(), isNot(newFile.uri.toFilePath())); + + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; + + expect(span.context.operation, 'file.copy'); + expect(span.data['file.size'], 7); + expect(span.data['file.async'], true); + expect(span.context.description, 'testfile.txt'); + expect( + (span.data['file.path'] as String) + .endsWith('test_resources/testfile.txt'), + true); + + await newFile.delete(); + }); + + test('copy sync', () async { + final file = File('test_resources/testfile.txt'); - test('copy wraps with a trace', () async { - final file = File('test.txt'); - await file.create(recursive: true); - expect(await file.exists(), true); + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); - final sut = fixture.getSut( - file, - sendDefaultPii: true, - tracesSampleRate: 1.0, - ); + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); - final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + final newFile = sut.copySync('test_resources/testfile_copy.txt'); - var newFile = await sut.copy('new.txt'); + await tr.finish(); - await tr.finish(); + final exists = newFile.existsSync(); + expect(exists, true); - final exists = await newFile.exists(); - expect(exists, true); + expect(sut.uri.toFilePath(), isNot(newFile.uri.toFilePath())); - expect(file.uri.toFilePath(), isNot(newFile.uri.toFilePath())); + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; - final call = fixture.client.captureTransactionCalls.first; - final span = call.transaction.spans.first; + expect(span.context.operation, 'file.copy'); + expect(span.data['file.size'], 7); + expect(span.data['file.async'], false); + expect(span.context.description, 'testfile.txt'); + expect( + (span.data['file.path'] as String) + .endsWith('test_resources/testfile.txt'), + true); - expect(span.context.operation, 'file.copy'); + await newFile.delete(); + }); }); } From 2f372ac95148e03a3f745a9e2847bd03d0e3e262 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 2 Dec 2022 12:31:02 +0100 Subject: [PATCH 05/23] add tests for create --- file/lib/src/sentry_file.dart | 30 ++++++---- file/test/sentry_file_test.dart | 99 ++++++++++++++++++++++++++------- 2 files changed, 97 insertions(+), 32 deletions(-) diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index d3d7e460c..7e188648c 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -185,6 +185,20 @@ class SentryFile implements File { ); } + void _setSize(ISentrySpan? span, dynamic data) { + // method that returns null dont have a size + if (data == null) { + return; + } + if (data is List) { + span?.setData('file.size', data.length); + } else if (data is File) { + span?.setData('file.size', data.lengthSync()); + // TODO: if its a copy, we need the new path here too or not? + // TODO: append size in bytes or human readable size + } + } + String _getDesc() { return uri.pathSegments.isNotEmpty ? uri.pathSegments.last : path; } @@ -202,13 +216,8 @@ class SentryFile implements File { T data; try { data = await future; - if (data is List) { - span?.setData('file.size', data.length); - } else if (data is File) { - span?.setData('file.size', await data.length()); - // TODO: if its a copy, we need the new path here too or not? - // TODO: append size in bytes or human readable size - } + _setSize(span, data); + span?.status = SpanStatus.ok(); } catch (exception) { span?.throwable = exception; @@ -233,11 +242,8 @@ class SentryFile implements File { T data; try { data = callback(); - if (data is List) { - span?.setData('file.size', data.length); - } else if (data is File) { - span?.setData('file.size', data.lengthSync()); - } + _setSize(span, data); + span?.status = SpanStatus.ok(); } catch (exception) { span?.throwable = exception; diff --git a/file/test/sentry_file_test.dart b/file/test/sentry_file_test.dart index 39bd016ad..caa44eb5b 100644 --- a/file/test/sentry_file_test.dart +++ b/file/test/sentry_file_test.dart @@ -18,6 +18,20 @@ void main() { fixture = Fixture(); }); + void _assertSpan(bool async) { + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; + + expect(span.context.operation, 'file.copy'); + expect(span.data['file.size'], 7); + expect(span.data['file.async'], async); + expect(span.context.description, 'testfile.txt'); + expect( + (span.data['file.path'] as String) + .endsWith('test_resources/testfile.txt'), + true); + } + test('copy async', () async { final file = File('test_resources/testfile.txt'); @@ -33,22 +47,11 @@ void main() { await tr.finish(); - final exists = await newFile.exists(); - expect(exists, true); + expect(await newFile.exists(), true); expect(sut.uri.toFilePath(), isNot(newFile.uri.toFilePath())); - final call = fixture.client.captureTransactionCalls.first; - final span = call.transaction.spans.first; - - expect(span.context.operation, 'file.copy'); - expect(span.data['file.size'], 7); - expect(span.data['file.async'], true); - expect(span.context.description, 'testfile.txt'); - expect( - (span.data['file.path'] as String) - .endsWith('test_resources/testfile.txt'), - true); + _assertSpan(true); await newFile.delete(); }); @@ -68,25 +71,81 @@ void main() { await tr.finish(); - final exists = newFile.existsSync(); - expect(exists, true); + expect(newFile.existsSync(), true); expect(sut.uri.toFilePath(), isNot(newFile.uri.toFilePath())); + _assertSpan(false); + + newFile.deleteSync(); + }); + }); + + group('$SentryFile create', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + void _assertSpan(bool async, {int? size = 0}) { final call = fixture.client.captureTransactionCalls.first; final span = call.transaction.spans.first; - expect(span.context.operation, 'file.copy'); - expect(span.data['file.size'], 7); - expect(span.data['file.async'], false); - expect(span.context.description, 'testfile.txt'); + expect(span.context.operation, 'file.write'); + expect(span.data['file.size'], size); + expect(span.data['file.async'], async); + expect(span.context.description, 'testfile_create.txt'); expect( (span.data['file.path'] as String) - .endsWith('test_resources/testfile.txt'), + .endsWith('test_resources/testfile_create.txt'), true); + } + + test('create async', () async { + final file = File('test_resources/testfile_create.txt'); + expect(await file.exists(), false); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + final newFile = await sut.create(); + + await tr.finish(); + + expect(await newFile.exists(), true); + + _assertSpan(true); await newFile.delete(); }); + + test('create sync', () async { + final file = File('test_resources/testfile_create.txt'); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + sut.createSync(); + + await tr.finish(); + + expect(sut.existsSync(), true); + + _assertSpan(false, size: null); + + sut.deleteSync(); + }); }); } From d6a5de6ec01036d095c3d6b7791a4ce9a6634c9f Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 2 Dec 2022 12:32:34 +0100 Subject: [PATCH 06/23] fix --- .github/workflows/file.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/file.yml b/.github/workflows/file.yml index 148cd3cf9..926fe7839 100644 --- a/.github/workflows/file.yml +++ b/.github/workflows/file.yml @@ -41,10 +41,9 @@ jobs: sdk: ${{ matrix.sdk }} - uses: actions/checkout@v3 # coverage with 'chrome' platform hangs the build - - name: Test (VM and browser) + - name: Test VM run: | dart pub get - dart test -p chrome --test-randomize-ordering-seed=random --chain-stack-traces dart test -p vm --coverage=coverage --test-randomize-ordering-seed=random --chain-stack-traces dart pub run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib From ac4d4dc926e3678fab8170da90cb85798c5eed05 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 2 Dec 2022 15:19:17 +0100 Subject: [PATCH 07/23] fixes --- .github/workflows/file.yml | 3 +- file/lib/src/sentry_file.dart | 94 ++++++++---- file/test/sentry_file_test.dart | 249 +++++++++++++++++++++++++++++++- file/test/version_test.dart | 2 + 4 files changed, 312 insertions(+), 36 deletions(-) diff --git a/.github/workflows/file.yml b/.github/workflows/file.yml index 926fe7839..6695ebb4c 100644 --- a/.github/workflows/file.yml +++ b/.github/workflows/file.yml @@ -31,7 +31,8 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - sdk: [stable, beta] + # removing beta because of Dart 2.19.0 + sdk: [stable] exclude: - os: macos-latest sdk: beta diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index 7e188648c..d87901409 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -2,13 +2,14 @@ // ignore_for_file: invalid_use_of_internal_member +import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:meta/meta.dart'; import 'package:sentry/sentry.dart'; -typedef Callback = T Function(); +typedef Callback = FutureOr Function(); class SentryFile implements File { SentryFile( @@ -21,7 +22,7 @@ class SentryFile implements File { @override Future copy(String newPath) { - return _wrap(_file.copy(newPath), 'file.copy'); + return _wrap(() async => _file.copy(newPath), 'file.copy'); } @override @@ -32,7 +33,7 @@ class SentryFile implements File { @override Future create({bool recursive = false}) { return _wrap( - _file.create(recursive: recursive), + () async => _file.create(recursive: recursive), 'file.write', ); } @@ -47,7 +48,7 @@ class SentryFile implements File { @override Future delete({bool recursive = false}) { - return _wrap(_file.delete(recursive: recursive), 'file.delete'); + return _wrap(() async => _file.delete(recursive: recursive), 'file.delete'); } @override @@ -57,7 +58,7 @@ class SentryFile implements File { @override Future open({FileMode mode = FileMode.read}) { - return _wrap(_file.open(mode: mode), 'file.open'); + return _wrap(() async => _file.open(mode: mode), 'file.open'); } // coverage:ignore-start @@ -81,7 +82,7 @@ class SentryFile implements File { @override Future readAsBytes() { - return _wrap(_file.readAsBytes(), 'file.read'); + return _wrap(() async => _file.readAsBytes(), 'file.read'); } @override @@ -91,7 +92,8 @@ class SentryFile implements File { @override Future> readAsLines({Encoding encoding = utf8}) { - return _wrap(_file.readAsLines(encoding: encoding), 'file.read'); + return _wrap( + () async => _file.readAsLines(encoding: encoding), 'file.read'); } @override @@ -104,7 +106,8 @@ class SentryFile implements File { @override Future readAsString({Encoding encoding = utf8}) { - return _wrap(_file.readAsString(encoding: encoding), 'file.read'); + return _wrap( + () async => _file.readAsString(encoding: encoding), 'file.read'); } @override @@ -117,7 +120,7 @@ class SentryFile implements File { @override Future rename(String newPath) { - return _wrap(_file.rename(newPath), 'file.rename'); + return _wrap(() async => _file.rename(newPath), 'file.rename'); } @override @@ -132,7 +135,7 @@ class SentryFile implements File { bool flush = false, }) { return _wrap( - _file.writeAsBytes(bytes, mode: mode, flush: flush), + () async => _file.writeAsBytes(bytes, mode: mode, flush: flush), 'file.write', ); } @@ -157,7 +160,7 @@ class SentryFile implements File { bool flush = false, }) { return _wrap( - _file.writeAsString( + () async => _file.writeAsString( contents, mode: mode, encoding: encoding, @@ -185,25 +188,11 @@ class SentryFile implements File { ); } - void _setSize(ISentrySpan? span, dynamic data) { - // method that returns null dont have a size - if (data == null) { - return; - } - if (data is List) { - span?.setData('file.size', data.length); - } else if (data is File) { - span?.setData('file.size', data.lengthSync()); - // TODO: if its a copy, we need the new path here too or not? - // TODO: append size in bytes or human readable size - } - } - String _getDesc() { return uri.pathSegments.isNotEmpty ? uri.pathSegments.last : path; } - Future _wrap(Future future, String operation) async { + Future _wrap(Callback callback, String operation) async { final desc = _getDesc(); final currentSpan = _hub.getSpan(); @@ -215,8 +204,30 @@ class SentryFile implements File { } T data; try { - data = await future; - _setSize(span, data); + // workaround for having the length when the file does not exist + // exists or its being deleted. + int? length; + var hasLength = false; + try { + length = await _file.length(); + hasLength = true; + } catch (_) { + // ignore in case something goes wrong + } + + data = await callback(); + + if (!hasLength) { + try { + length = await _file.length(); + } catch (_) { + // ignore in case something goes wrong + } + } + + if (length != null) { + span?.setData('file.size', length); + } span?.status = SpanStatus.ok(); } catch (exception) { @@ -239,10 +250,33 @@ class SentryFile implements File { if (_hub.options.sendDefaultPii) { span?.setData('file.path', absolute.path); } + T data; try { - data = callback(); - _setSize(span, data); + // workaround for having the length when the file does not exist + // exists or its being deleted. + int? length; + var hasLength = false; + try { + length = _file.lengthSync(); + hasLength = true; + } catch (_) { + // ignore in case something goes wrong + } + + data = callback() as T; + + if (!hasLength) { + try { + length = _file.lengthSync(); + } catch (_) { + // ignore in case something goes wrong + } + } + + if (length != null) { + span?.setData('file.size', length); + } span?.status = SpanStatus.ok(); } catch (exception) { diff --git a/file/test/sentry_file_test.dart b/file/test/sentry_file_test.dart index caa44eb5b..696b853d7 100644 --- a/file/test/sentry_file_test.dart +++ b/file/test/sentry_file_test.dart @@ -32,7 +32,7 @@ void main() { true); } - test('copy async', () async { + test('async', () async { final file = File('test_resources/testfile.txt'); final sut = fixture.getSut( @@ -56,7 +56,7 @@ void main() { await newFile.delete(); }); - test('copy sync', () async { + test('sync', () async { final file = File('test_resources/testfile.txt'); final sut = fixture.getSut( @@ -102,7 +102,7 @@ void main() { true); } - test('create async', () async { + test('async', () async { final file = File('test_resources/testfile_create.txt'); expect(await file.exists(), false); @@ -125,8 +125,9 @@ void main() { await newFile.delete(); }); - test('create sync', () async { + test('sync', () async { final file = File('test_resources/testfile_create.txt'); + expect(await file.exists(), false); final sut = fixture.getSut( file, @@ -142,9 +143,247 @@ void main() { expect(sut.existsSync(), true); - _assertSpan(false, size: null); + _assertSpan(false); + + sut.deleteSync(); + }); + }); + + group('$SentryFile delete', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + void _assertSpan(bool async, {int? size = 0}) { + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; + + expect(span.context.operation, 'file.delete'); + expect(span.data['file.size'], size); + expect(span.data['file.async'], async); + expect(span.context.description, 'testfile_delete.txt'); + expect( + (span.data['file.path'] as String) + .endsWith('test_resources/testfile_delete.txt'), + true); + } + + test('async', () async { + final file = File('test_resources/testfile_delete.txt'); + await file.create(); + expect(await file.exists(), true); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + final newFile = await sut.delete(); + + await tr.finish(); + + expect(await newFile.exists(), false); + + _assertSpan(true); + }); + + test('sync', () async { + final file = File('test_resources/testfile_delete.txt'); + file.createSync(); + expect(file.existsSync(), true); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); sut.deleteSync(); + + await tr.finish(); + + expect(sut.existsSync(), false); + + _assertSpan(false); + }); + }); + + group('$SentryFile open', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + void _assertSpan() { + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; + + expect(span.context.operation, 'file.open'); + expect(span.data['file.size'], 3535); + expect(span.data['file.async'], true); + expect(span.context.description, 'sentry.png'); + expect( + (span.data['file.path'] as String) + .endsWith('test_resources/sentry.png'), + true); + } + + test('async', () async { + final file = File('test_resources/sentry.png'); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + final newFile = await sut.open(); + + await tr.finish(); + + await newFile.close(); + + _assertSpan(); + }); + }); + + group('$SentryFile read', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + void _assertSpan(String fileName, bool async, {int? size = 0}) { + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; + + expect(span.context.operation, 'file.read'); + expect(span.data['file.size'], size); + expect(span.data['file.async'], async); + expect(span.context.description, fileName); + expect( + (span.data['file.path'] as String) + .endsWith('test_resources/$fileName'), + true); + } + + test('as bytes async', () async { + final file = File('test_resources/sentry.png'); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + await sut.readAsBytes(); + + await tr.finish(); + + _assertSpan('sentry.png', true, size: 3535); + }); + + test('as bytes sync', () async { + final file = File('test_resources/sentry.png'); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + sut.readAsBytesSync(); + + await tr.finish(); + + _assertSpan('sentry.png', false, size: 3535); + }); + + test('lines async', () async { + final file = File('test_resources/testfile.txt'); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + await sut.readAsLines(); + + await tr.finish(); + + _assertSpan('testfile.txt', true, size: 7); + }); + + test('lines sync', () async { + final file = File('test_resources/testfile.txt'); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + sut.readAsLinesSync(); + + await tr.finish(); + + _assertSpan('testfile.txt', false, size: 7); + }); + + test('string async', () async { + final file = File('test_resources/testfile.txt'); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + await sut.readAsString(); + + await tr.finish(); + + _assertSpan('testfile.txt', true, size: 7); + }); + + test('string sync', () async { + final file = File('test_resources/testfile.txt'); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + sut.readAsStringSync(); + + await tr.finish(); + + _assertSpan('testfile.txt', false, size: 7); }); }); } diff --git a/file/test/version_test.dart b/file/test/version_test.dart index 8bba9116b..57d12e357 100644 --- a/file/test/version_test.dart +++ b/file/test/version_test.dart @@ -1,3 +1,5 @@ +// ignore_for_file: depend_on_referenced_packages + @TestOn('vm') import 'dart:io'; From 05ea2c9bbbe7786ac2dd8b713746dd622ed6281b Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 12:17:06 +0100 Subject: [PATCH 08/23] add missing tests --- file/lib/src/sentry_file.dart | 4 +- file/new.txt | 0 file/test/sentry_file_test.dart | 123 ++++++++++++++++++++++++++++++++ scripts/bump-version.sh | 2 +- 4 files changed, 126 insertions(+), 3 deletions(-) delete mode 100644 file/new.txt diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index d87901409..442682f61 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -205,7 +205,7 @@ class SentryFile implements File { T data; try { // workaround for having the length when the file does not exist - // exists or its being deleted. + // or its being deleted. int? length; var hasLength = false; try { @@ -254,7 +254,7 @@ class SentryFile implements File { T data; try { // workaround for having the length when the file does not exist - // exists or its being deleted. + // or its being deleted. int? length; var hasLength = false; try { diff --git a/file/new.txt b/file/new.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/file/test/sentry_file_test.dart b/file/test/sentry_file_test.dart index 696b853d7..e773294c5 100644 --- a/file/test/sentry_file_test.dart +++ b/file/test/sentry_file_test.dart @@ -386,6 +386,129 @@ void main() { _assertSpan('testfile.txt', false, size: 7); }); }); + + group('$SentryFile rename', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + void _assertSpan(bool async, String name) { + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; + + expect(span.context.operation, 'file.rename'); + expect(span.data['file.size'], 0); + expect(span.data['file.async'], async); + expect(span.context.description, name); + expect( + (span.data['file.path'] as String).endsWith('test_resources/$name'), + true); + } + + test('async', () async { + final file = File('test_resources/old_name.txt'); + await file.create(); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + final newFile = await sut.rename('test_resources/new_name.txt'); + + await tr.finish(); + + expect(await file.exists(), false); + expect(await newFile.exists(), true); + + expect(sut.uri.toFilePath(), isNot(newFile.uri.toFilePath())); + + _assertSpan(true, 'old_name.txt'); + + await newFile.delete(); + }); + + test('sync', () async { + final file = File('test_resources/old_name.txt'); + file.createSync(); + + final sut = fixture.getSut( + file, + sendDefaultPii: true, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + final newFile = sut.renameSync('test_resources/testfile_copy.txt'); + + await tr.finish(); + + expect(file.existsSync(), false); + expect(newFile.existsSync(), true); + + expect(sut.uri.toFilePath(), isNot(newFile.uri.toFilePath())); + + _assertSpan(false, 'old_name.txt'); + + newFile.deleteSync(); + }); + }); + + group('$SentryOptions sendDefaultPii', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + void _assertSpan(bool async) { + final call = fixture.client.captureTransactionCalls.first; + final span = call.transaction.spans.first; + + expect(span.data['file.async'], async); + expect(span.data['file.path'], null); + } + + test('does not add file path async', () async { + final file = File('test_resources/testfile.txt'); + + final sut = fixture.getSut( + file, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + await sut.readAsBytes(); + + await tr.finish(); + + _assertSpan(true); + }); + + test('sync', () async { + final file = File('test_resources/testfile.txt'); + + final sut = fixture.getSut( + file, + tracesSampleRate: 1.0, + ); + + final tr = fixture.hub.startTransaction('name', 'op', bindToScope: true); + + sut.readAsBytesSync(); + + await tr.finish(); + + _assertSpan(false); + }); + }); } class Fixture { diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index 690701561..e8c23baa7 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -10,7 +10,7 @@ NEW_VERSION="${2}" echo "Current version: ${OLD_VERSION}" echo "Bumping version: ${NEW_VERSION}" -for pkg in {dart,flutter,logging,dio}; do +for pkg in {dart,flutter,logging,dio,file}; do # Bump version in pubspec.yaml perl -pi -e "s/^version: .*/version: $NEW_VERSION/" $pkg/pubspec.yaml # Bump sentry dependency version in pubspec.yaml From 153813bcef72e42535de69a70c04a503994463d5 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 12:17:35 +0100 Subject: [PATCH 09/23] remove --- file/test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 file/test.txt diff --git a/file/test.txt b/file/test.txt deleted file mode 100644 index e69de29bb..000000000 From 13124533c313d6b4ba737908e1a05639a806e327 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 12:31:09 +0100 Subject: [PATCH 10/23] add extension --- file/lib/sentry_file.dart | 1 + file/lib/src/sentry_file.dart | 15 +++++++++++++++ file/lib/src/sentry_file_extension.dart | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 file/lib/src/sentry_file_extension.dart diff --git a/file/lib/sentry_file.dart b/file/lib/sentry_file.dart index 35ceec610..bd59fdea5 100644 --- a/file/lib/sentry_file.dart +++ b/file/lib/sentry_file.dart @@ -1 +1,2 @@ export 'src/sentry_file.dart'; +export 'src/sentry_file_extension.dart'; diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index 442682f61..644edefa5 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -11,6 +11,21 @@ import 'package:sentry/sentry.dart'; typedef Callback = FutureOr Function(); +/// The Sentry wrapper for the File implementation that starts a span +/// out of the active transaction in the scope. +/// The span is started before the operation is executed and finished after. +/// Example: +/// +/// ```dart +/// final file = File('test.txt'); +/// final sentryFile = SentryFile(file); +/// // span starts +/// await sentryFile.writeAsString('Hello World'); +/// // span finishes +/// ``` +/// +/// All the copy, create, delete, open, rename, read, and write operations are +/// supported. class SentryFile implements File { SentryFile( this._file, { diff --git a/file/lib/src/sentry_file_extension.dart b/file/lib/src/sentry_file_extension.dart new file mode 100644 index 000000000..6a96ed04e --- /dev/null +++ b/file/lib/src/sentry_file_extension.dart @@ -0,0 +1,24 @@ +import 'dart:io'; + +import '../sentry_file.dart'; + +extension SentryFileExtension on File { + /// The Sentry wrapper for the File implementation that starts a span + /// out of the active transaction in the scope. + /// The span is started before the operation is executed and finished after. + /// Example: + /// + /// ```dart + /// final file = File('test.txt'); + /// final sentryFile = file.sentryTrace(); + /// // span starts + /// await sentryFile.writeAsString('Hello World'); + /// // span finishes + /// ``` + /// + /// All the copy, create, delete, open, rename, read, and write operations are + /// supported. + SentryFile sentryTrace() { + return SentryFile(this); + } +} From 244a6f4b422d9ecfcc5ab59658b34eb631fedb42 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 13:22:31 +0100 Subject: [PATCH 11/23] fixes --- file/lib/src/sentry_file.dart | 6 ++- file/lib/src/sentry_file_extension.dart | 28 ++++++++-- file/test/mock_platform_checker.dart | 11 ++++ file/test/sentry_file_extension_test.dart | 64 +++++++++++++++++++++++ 4 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 file/test/mock_platform_checker.dart create mode 100644 file/test/sentry_file_extension_test.dart diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index 644edefa5..d3f21d3b2 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -11,12 +11,16 @@ import 'package:sentry/sentry.dart'; typedef Callback = FutureOr Function(); -/// The Sentry wrapper for the File implementation that starts a span +/// The Sentry wrapper for the File IO implementation that creates a span /// out of the active transaction in the scope. /// The span is started before the operation is executed and finished after. +/// The File tracing isn't available for Web. +/// /// Example: /// /// ```dart +/// import 'dart:io'; +/// /// final file = File('test.txt'); /// final sentryFile = SentryFile(file); /// // span starts diff --git a/file/lib/src/sentry_file_extension.dart b/file/lib/src/sentry_file_extension.dart index 6a96ed04e..f6f0c70de 100644 --- a/file/lib/src/sentry_file_extension.dart +++ b/file/lib/src/sentry_file_extension.dart @@ -1,16 +1,25 @@ -import 'dart:io'; +// ignore_for_file: invalid_use_of_internal_member + +import 'dart:io' if (dart.library.html) 'dart:html'; + +import 'package:meta/meta.dart'; +import 'package:sentry/sentry.dart'; import '../sentry_file.dart'; extension SentryFileExtension on File { - /// The Sentry wrapper for the File implementation that starts a span + /// The Sentry wrapper for the File IO implementation that creates a span /// out of the active transaction in the scope. /// The span is started before the operation is executed and finished after. + /// The File tracing isn't available for Web. + /// /// Example: /// /// ```dart + /// import 'dart:io'; + /// /// final file = File('test.txt'); - /// final sentryFile = file.sentryTrace(); + /// final sentryFile = SentryFile(file); /// // span starts /// await sentryFile.writeAsString('Hello World'); /// // span finishes @@ -18,7 +27,16 @@ extension SentryFileExtension on File { /// /// All the copy, create, delete, open, rename, read, and write operations are /// supported. - SentryFile sentryTrace() { - return SentryFile(this); + File sentryTrace({ + @internal Hub? hub, + }) { + final _hub = hub ?? HubAdapter(); + + if (_hub.options.platformChecker.isWeb || + !_hub.options.isTracingEnabled()) { + return this; + } + + return SentryFile(this, hub: _hub); } } diff --git a/file/test/mock_platform_checker.dart b/file/test/mock_platform_checker.dart new file mode 100644 index 000000000..6dd95a5c0 --- /dev/null +++ b/file/test/mock_platform_checker.dart @@ -0,0 +1,11 @@ +import 'no_such_method_provider.dart'; +import 'package:sentry/src/platform_checker.dart'; + +class MockPlatformChecker extends PlatformChecker with NoSuchMethodProvider { + MockPlatformChecker(this._isWeb); + + final bool _isWeb; + + @override + bool get isWeb => _isWeb; +} diff --git a/file/test/sentry_file_extension_test.dart b/file/test/sentry_file_extension_test.dart new file mode 100644 index 000000000..73eb94bef --- /dev/null +++ b/file/test/sentry_file_extension_test.dart @@ -0,0 +1,64 @@ +@TestOn('vm') + +import 'dart:io'; + +import 'package:sentry/sentry.dart'; +import 'package:sentry_file/sentry_file.dart'; +import 'package:test/test.dart'; + +import 'mock_platform_checker.dart'; +import 'mock_sentry_client.dart'; + +void main() { + group('$File extension', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('io performance enabled wraps file', () async { + final sut = fixture.getSut( + tracesSampleRate: 1.0, + ); + + expect(sut is SentryFile, true); + }); + + test('io performance disabled does not wrap file', () async { + final sut = fixture.getSut( + tracesSampleRate: null, + ); + + expect(sut is SentryFile, false); + }); + + test('web does not wrap file', () async { + final sut = fixture.getSut( + tracesSampleRate: 1.0, + isWeb: true, + ); + + expect(sut is SentryFile, false); + }); + }); +} + +class Fixture { + final options = SentryOptions(dsn: fakeDsn); + late Hub hub; + + File getSut({ + double? tracesSampleRate, + bool isWeb = false, + }) { + options.tracesSampleRate = tracesSampleRate; + options.platformChecker = MockPlatformChecker(isWeb); + + hub = Hub(options); + + final file = File('test_resources/testfile.txt'); + + return file.sentryTrace(hub: hub); + } +} From 00cd84a62c767452a61bd8d1562ccdb84ebfa90b Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 13:35:39 +0100 Subject: [PATCH 12/23] add example --- file/example/example.dart | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/file/example/example.dart b/file/example/example.dart index 03477bfcf..85d1898f0 100644 --- a/file/example/example.dart +++ b/file/example/example.dart @@ -1,4 +1,6 @@ import 'package:sentry/sentry.dart'; +import 'package:sentry_file/sentry_file.dart'; +import 'dart:io'; Future main() async { // ATTENTION: Change the DSN below with your own to see the events in Sentry. Get one at sentry.io @@ -8,9 +10,33 @@ Future main() async { await Sentry.init( (options) { options.dsn = dsn; + options.debug = true; + options.sendDefaultPii = true; + options.tracesSampleRate = 1.0; }, appRunner: runApp, // Init your App. ); } -Future runApp() async {} +Future runApp() async { + final file = File('my_file.txt'); + final sentryFile = file.sentryTrace(); + + final transaction = Sentry.startTransaction( + 'MyFileExample', + 'file', + bindToScope: true, + ); + + await sentryFile.create(); + await sentryFile.writeAsString('Hello World'); + final text = await sentryFile.readAsString(); + + print(text); + + await sentryFile.delete(); + + await transaction.finish(status: SpanStatus.ok()); + + await Sentry.close(); +} From 5ce347d0ab08502c3fb749f442967d65cb5826df Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 13:51:58 +0100 Subject: [PATCH 13/23] add readme --- file/README.md | 48 +++++++++++++++++++++++++++++++++++++++ file/example/example.dart | 11 ++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/file/README.md b/file/README.md index 7eca7b509..be8c29550 100644 --- a/file/README.md +++ b/file/README.md @@ -20,6 +20,54 @@ Sentry integration for `dart.io.File` - Initialize the Sentry SDK using the DSN issued by Sentry.io. +```dart +import 'package:sentry/sentry.dart'; +import 'package:sentry_file/sentry_file.dart'; +import 'dart:io'; + +Future main() async { + // or SentryFlutter.init + await Sentry.init( + (options) { + options.dsn = 'https://example@sentry.io/example'; + // to enable Performance Monitoring + options.tracesSampleRate = 1.0; + }, + appRunner: runApp, // Init your App. + ); +} + +Future runApp() async { + final file = File('my_file.txt'); + // call the Sentry extension method to wrap the File + final sentryFile = file.sentryTrace(); + + // Start a transaction if there's no active transaction + final transaction = Sentry.startTransaction( + 'MyFileExample', + 'file', + bindToScope: true, + ); + + // create the File + await sentryFile.create(); + // write some content + await sentryFile.writeAsString('Hello World'); + // read the content + final text = await sentryFile.readAsString(); + + print(text); + + // delete the file + await sentryFile.delete(); + + // finish the transaction + await transaction.finish(status: SpanStatus.ok()); + + await Sentry.close(); +} +``` + #### Resources * [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dart/) diff --git a/file/example/example.dart b/file/example/example.dart index 85d1898f0..a182b8fa7 100644 --- a/file/example/example.dart +++ b/file/example/example.dart @@ -7,11 +7,13 @@ Future main() async { const dsn = 'https://e85b375ffb9f43cf8bdf9787768149e0@o447951.ingest.sentry.io/5428562'; + // or SentryFlutter.init await Sentry.init( (options) { options.dsn = dsn; - options.debug = true; + // to capture the absolute path of the file options.sendDefaultPii = true; + // to enable Performance Monitoring options.tracesSampleRate = 1.0; }, appRunner: runApp, // Init your App. @@ -20,22 +22,29 @@ Future main() async { Future runApp() async { final file = File('my_file.txt'); + // call the Sentry extension method to wrap the File final sentryFile = file.sentryTrace(); + // Start a transaction if there's no active transaction final transaction = Sentry.startTransaction( 'MyFileExample', 'file', bindToScope: true, ); + // create the File await sentryFile.create(); + // write some content await sentryFile.writeAsString('Hello World'); + // read the content final text = await sentryFile.readAsString(); print(text); + // delete the file await sentryFile.delete(); + // finish the transaction await transaction.finish(status: SpanStatus.ok()); await Sentry.close(); From 74a42f16299f93c3cfdff386fdd4dfab6d174266 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 13:56:43 +0100 Subject: [PATCH 14/23] fixes comments --- file/README.md | 14 ++++++++------ file/example/example.dart | 16 ++++++++-------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/file/README.md b/file/README.md index be8c29550..700706d41 100644 --- a/file/README.md +++ b/file/README.md @@ -20,6 +20,8 @@ Sentry integration for `dart.io.File` - Initialize the Sentry SDK using the DSN issued by Sentry.io. +- [Set Up](https://docs.sentry.io/platforms/dart/performance/) Performance. + ```dart import 'package:sentry/sentry.dart'; import 'package:sentry_file/sentry_file.dart'; @@ -30,7 +32,7 @@ Future main() async { await Sentry.init( (options) { options.dsn = 'https://example@sentry.io/example'; - // to enable Performance Monitoring + // To set a uniform sample rate options.tracesSampleRate = 1.0; }, appRunner: runApp, // Init your App. @@ -39,7 +41,7 @@ Future main() async { Future runApp() async { final file = File('my_file.txt'); - // call the Sentry extension method to wrap the File + // Call the Sentry extension method to wrap up the File final sentryFile = file.sentryTrace(); // Start a transaction if there's no active transaction @@ -51,17 +53,17 @@ Future runApp() async { // create the File await sentryFile.create(); - // write some content + // Write some content await sentryFile.writeAsString('Hello World'); - // read the content + // Read the content final text = await sentryFile.readAsString(); print(text); - // delete the file + // Delete the file await sentryFile.delete(); - // finish the transaction + // Finish the transaction await transaction.finish(status: SpanStatus.ok()); await Sentry.close(); diff --git a/file/example/example.dart b/file/example/example.dart index a182b8fa7..1423efe4a 100644 --- a/file/example/example.dart +++ b/file/example/example.dart @@ -11,9 +11,9 @@ Future main() async { await Sentry.init( (options) { options.dsn = dsn; - // to capture the absolute path of the file + // To capture the absolute path of the file options.sendDefaultPii = true; - // to enable Performance Monitoring + // To set a uniform sample rate options.tracesSampleRate = 1.0; }, appRunner: runApp, // Init your App. @@ -22,7 +22,7 @@ Future main() async { Future runApp() async { final file = File('my_file.txt'); - // call the Sentry extension method to wrap the File + // Call the Sentry extension method to wrap up the File final sentryFile = file.sentryTrace(); // Start a transaction if there's no active transaction @@ -32,19 +32,19 @@ Future runApp() async { bindToScope: true, ); - // create the File + // Create the File await sentryFile.create(); - // write some content + // Write some content await sentryFile.writeAsString('Hello World'); - // read the content + // Read the content final text = await sentryFile.readAsString(); print(text); - // delete the file + // Delete the file await sentryFile.delete(); - // finish the transaction + // Finish the transaction await transaction.finish(status: SpanStatus.ok()); await Sentry.close(); From 52bf20d5c27daccc0f0b0fb6ca94f2befed7758d Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 14:02:36 +0100 Subject: [PATCH 15/23] enable strict analyzer --- file/analysis_options.yaml | 9 ++++----- file/lib/src/sentry_file.dart | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/file/analysis_options.yaml b/file/analysis_options.yaml index c5924fcb2..3dd01b96b 100644 --- a/file/analysis_options.yaml +++ b/file/analysis_options.yaml @@ -8,11 +8,10 @@ analyzer: missing_required_param: error # treat missing returns as a warning (not a hint) missing_return: error - # allow having TODOs in the code - todo: ignore - # allow self-reference to deprecated members (we do this because otherwise we have - # to annotate every member in every test, assert, etc, when we deprecate something) - deprecated_member_use_from_same_package: warning + language: + strict-casts: true + strict-inference: true + strict-raw-types: true linter: rules: diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index d3f21d3b2..88f76ed75 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -324,13 +324,13 @@ class SentryFile implements File { String resolveSymbolicLinksSync() => _file.resolveSymbolicLinksSync(); @override - Future setLastAccessed(DateTime time) => _file.setLastAccessed(time); + Future setLastAccessed(DateTime time) => _file.setLastAccessed(time); @override void setLastAccessedSync(DateTime time) => _file.setLastAccessedSync(time); @override - Future setLastModified(DateTime time) => _file.setLastModified(time); + Future setLastModified(DateTime time) => _file.setLastModified(time); @override void setLastModifiedSync(DateTime time) => _file.setLastAccessedSync(time); From e39ecc7f8db7815ab3d40a2c0f40b8deb2a75fee Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 14:14:34 +0100 Subject: [PATCH 16/23] add integration --- file/lib/src/sentry_file.dart | 4 +++- file/test/sentry_file_test.dart | 21 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index 88f76ed75..5680b76aa 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -34,7 +34,9 @@ class SentryFile implements File { SentryFile( this._file, { @internal Hub? hub, - }) : _hub = hub ?? HubAdapter(); + }) : _hub = hub ?? HubAdapter() { + _hub.options.sdk.addIntegration('SentryFileTracing'); + } final File _file; final Hub _hub; diff --git a/file/test/sentry_file_test.dart b/file/test/sentry_file_test.dart index e773294c5..74b10ac8c 100644 --- a/file/test/sentry_file_test.dart +++ b/file/test/sentry_file_test.dart @@ -1,3 +1,5 @@ +// ignore_for_file: invalid_use_of_internal_member + @TestOn('vm') import 'dart:io'; @@ -460,7 +462,7 @@ void main() { }); }); - group('$SentryOptions sendDefaultPii', () { + group('$SentryOptions config', () { late Fixture fixture; setUp(() { @@ -475,7 +477,8 @@ void main() { expect(span.data['file.path'], null); } - test('does not add file path async', () async { + test('does not add file path if sendDefaultPii is disabled async', + () async { final file = File('test_resources/testfile.txt'); final sut = fixture.getSut( @@ -492,7 +495,7 @@ void main() { _assertSpan(true); }); - test('sync', () async { + test('does not add file path if sendDefaultPii is disabled sync', () async { final file = File('test_resources/testfile.txt'); final sut = fixture.getSut( @@ -508,6 +511,18 @@ void main() { _assertSpan(false); }); + + test('add SentryFileTracing integration', () async { + final file = File('test_resources/testfile.txt'); + + fixture.getSut( + file, + tracesSampleRate: 1.0, + ); + + expect(fixture.hub.options.sdk.integrations.contains('SentryFileTracing'), + true); + }); }); } From 184166976cb52386623ace025796bc3c9d3b57f5 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 14:15:18 +0100 Subject: [PATCH 17/23] add @experimental annotation --- file/lib/src/sentry_file.dart | 1 + file/lib/src/sentry_file_extension.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/file/lib/src/sentry_file.dart b/file/lib/src/sentry_file.dart index 5680b76aa..36cd88034 100644 --- a/file/lib/src/sentry_file.dart +++ b/file/lib/src/sentry_file.dart @@ -30,6 +30,7 @@ typedef Callback = FutureOr Function(); /// /// All the copy, create, delete, open, rename, read, and write operations are /// supported. +@experimental class SentryFile implements File { SentryFile( this._file, { diff --git a/file/lib/src/sentry_file_extension.dart b/file/lib/src/sentry_file_extension.dart index f6f0c70de..2c2f2657f 100644 --- a/file/lib/src/sentry_file_extension.dart +++ b/file/lib/src/sentry_file_extension.dart @@ -27,6 +27,7 @@ extension SentryFileExtension on File { /// /// All the copy, create, delete, open, rename, read, and write operations are /// supported. + @experimental File sentryTrace({ @internal Hub? hub, }) { From a794e141ce965ce1d9280aef7351163caf74b82e Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Mon, 5 Dec 2022 14:40:15 +0100 Subject: [PATCH 18/23] overwrite pana threshold --- .github/workflows/file.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/file.yml b/.github/workflows/file.yml index 6695ebb4c..08aeaa929 100644 --- a/.github/workflows/file.yml +++ b/.github/workflows/file.yml @@ -58,9 +58,10 @@ jobs: if: runner.os == 'Linux' && matrix.sdk == 'stable' with: path: './file/coverage/lcov.info' - min_coverage: 81 + min_coverage: 55 analyze: uses: ./.github/workflows/analyze.yml with: package: file + panaThreshold: 90 From 6fe96871991d8748cd55c4f874a3a254bf4cdd1f Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Mon, 5 Dec 2022 17:30:34 +0100 Subject: [PATCH 19/23] Update .craft.yml --- .craft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.craft.yml b/.craft.yml index 181e929f4..0967399ec 100644 --- a/.craft.yml +++ b/.craft.yml @@ -17,4 +17,4 @@ targets: pub:sentry_flutter: pub:sentry_logging: pub:sentry_dio: - #pub:sentry_dio: + #pub:sentry_file: From 7b46c5cabc87b12a99c01160bb389ab85e7445d9 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Tue, 6 Dec 2022 09:45:45 +0100 Subject: [PATCH 20/23] remove not needed items from gh action --- .github/workflows/file.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/file.yml b/.github/workflows/file.yml index 08aeaa929..3889deac2 100644 --- a/.github/workflows/file.yml +++ b/.github/workflows/file.yml @@ -33,15 +33,12 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] # removing beta because of Dart 2.19.0 sdk: [stable] - exclude: - - os: macos-latest - sdk: beta steps: - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d # pin@v1 with: sdk: ${{ matrix.sdk }} - uses: actions/checkout@v3 - # coverage with 'chrome' platform hangs the build + - name: Test VM run: | dart pub get From 88b619463a0b6085a81f7dcbf242f902a1f3eeb6 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Tue, 6 Dec 2022 11:20:30 +0100 Subject: [PATCH 21/23] add dart file to min test --- .github/workflows/min_version_test.yml | 1 + min_version_test/lib/main.dart | 60 +++++++++++++++++++++----- min_version_test/pubspec.yaml | 3 ++ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/.github/workflows/min_version_test.yml b/.github/workflows/min_version_test.yml index dcd8ad3f2..e96f18cb8 100644 --- a/.github/workflows/min_version_test.yml +++ b/.github/workflows/min_version_test.yml @@ -38,3 +38,4 @@ jobs: flutter pub get flutter build ios --no-codesign flutter build appbundle + flutter build web diff --git a/min_version_test/lib/main.dart b/min_version_test/lib/main.dart index f4b277b18..e70e318bf 100644 --- a/min_version_test/lib/main.dart +++ b/min_version_test/lib/main.dart @@ -1,25 +1,52 @@ import 'package:flutter/material.dart'; +import 'dart:io' if (dart.library.html) 'dart:html'; + import 'package:logging/logging.dart'; import 'package:dio/dio.dart'; +import 'package:sentry/sentry.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_dio/sentry_dio.dart'; import 'package:sentry_logging/sentry_logging.dart'; +import 'package:sentry_file/sentry_file.dart'; // ATTENTION: Change the DSN below with your own to see the events in Sentry. Get one at sentry.io const String _exampleDsn = 'https://e85b375ffb9f43cf8bdf9787768149e0@o447951.ingest.sentry.io/5428562'; Future main() async { - await SentryFlutter.init( - (options) { - options.dsn = _exampleDsn; - options.addIntegration(LoggingIntegration()); - }, - // Init your App. - appRunner: () => runApp(const MyApp()), - ); + await setupSentry(() => runApp( + SentryScreenshotWidget( + child: SentryUserInteractionWidget( + child: DefaultAssetBundle( + bundle: SentryAssetBundle(enableStructuredDataTracing: true), + child: const MyApp(), + ), + ), + ), + )); +} + +Future setupSentry(AppRunner appRunner) async { + await SentryFlutter.init((options) { + options.dsn = _exampleDsn; + options.tracesSampleRate = 1.0; + options.attachThreads = true; + options.enableWindowMetricBreadcrumbs = true; + options.addIntegration(LoggingIntegration()); + options.sendDefaultPii = true; + options.reportSilentFlutterErrors = true; + options.enableNdkScopeSync = true; + options.enableUserInteractionTracing = true; + options.attachScreenshot = true; + // We can enable Sentry debug logging during development. This is likely + // going to log too much for your app, but can be useful when figuring out + // configuration issues, e.g. finding out why your events are not uploaded. + options.debug = true; + }, + // Init your App. + appRunner: appRunner); } class MyApp extends StatelessWidget { @@ -70,6 +97,12 @@ class _MyHomePageState extends State { Future _incrementCounter() async { setState(() async { + final transaction = Sentry.startTransaction( + 'incrementCounter', + 'task', + bindToScope: true, + ); + // This call to setState tells the Flutter framework that something has // changed in this State, which causes it to rerun the build method below // so that the display can reflect the updated values. If we changed @@ -78,12 +111,19 @@ class _MyHomePageState extends State { _counter++; final dio = Dio(); - dio.addSentry(); + dio.addSentry(captureFailedRequests: true); final log = Logger('_MyHomePageState'); + try { - await dio.get('https://flutter.dev/'); + final file = File('response.txt'); + final sentryFile = file.sentryTrace(); + final response = await dio.get('https://flutter.dev/'); + await sentryFile.writeAsString(response.data ?? 'no response'); + + await transaction.finish(status: SpanStatus.ok()); } catch (exception, stackTrace) { log.info(exception.toString(), exception, stackTrace); + await transaction.finish(status: SpanStatus.internalError()); } }); } diff --git a/min_version_test/pubspec.yaml b/min_version_test/pubspec.yaml index 368deb46d..4ecca9a59 100644 --- a/min_version_test/pubspec.yaml +++ b/min_version_test/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: sentry_flutter: sentry_dio: sentry_logging: + sentry_file: dio: ^4.0.0 logging: ^1.0.0 @@ -52,6 +53,8 @@ dependency_overrides: path: ../dio sentry_logging: path: ../logging + sentry_file: + path: ../file # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec From 964eb27b66800b4014afc26d0d60c7a66fc32926 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Tue, 6 Dec 2022 11:56:34 +0100 Subject: [PATCH 22/23] add example --- .github/workflows/min_version_test.yml | 3 +- flutter/example/lib/main.dart | 47 ++++++++++++++++++++++++++ flutter/example/pubspec.yaml | 2 ++ flutter/example/pubspec_overrides.yaml | 2 ++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/.github/workflows/min_version_test.yml b/.github/workflows/min_version_test.yml index e96f18cb8..a39e13a5a 100644 --- a/.github/workflows/min_version_test.yml +++ b/.github/workflows/min_version_test.yml @@ -31,11 +31,10 @@ jobs: - uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d # pin@v2 with: flutter-version: '2.0.0' - + # Add flutter build web (missing index) - name: Build run: | cd min_version_test flutter pub get flutter build ios --no-codesign flutter build appbundle - flutter build web diff --git a/flutter/example/lib/main.dart b/flutter/example/lib/main.dart index 46665eadf..accd987e3 100644 --- a/flutter/example/lib/main.dart +++ b/flutter/example/lib/main.dart @@ -3,6 +3,9 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io' if (dart.library.html) 'dart:html'; +import 'package:path_provider/path_provider.dart'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -15,6 +18,7 @@ import 'user_feedback_dialog.dart'; import 'package:dio/dio.dart'; import 'package:sentry_dio/sentry_dio.dart'; import 'package:sentry_logging/sentry_logging.dart'; +import 'package:sentry_file/sentry_file.dart'; // ATTENTION: Change the DSN below with your own to see the events in Sentry. Get one at sentry.io const String _exampleDsn = @@ -339,6 +343,12 @@ class MainScaffold extends StatelessWidget { }, child: const Text('Capture User Feedback'), ), + ElevatedButton( + onPressed: () async { + await _manipulateFile(); + }, + child: const Text('Manipulate file'), + ), ElevatedButton( onPressed: () async { await showDialog( @@ -663,6 +673,43 @@ Future showDialogWithTextAndImage(BuildContext context) async { await transaction.finish(status: const SpanStatus.ok()); } +Future get _localPath async { + final directory = await getApplicationDocumentsDirectory(); + + return directory.path; +} + +Future get _localFile async { + final path = await _localPath; + return File('$path/response.txt'); +} + +Future _manipulateFile() async { + final transaction = Sentry.getSpan() ?? + Sentry.startTransaction( + 'MyFileExample', + 'file', + bindToScope: true, + ); + + final dio = Dio(); + dio.addSentry(captureFailedRequests: true); + + try { + final file = await _localFile; + final sentryFile = file.sentryTrace(); + if (!await sentryFile.exists()) { + await sentryFile.create(); + } + final response = await dio.get('https://flutter.dev/'); + await sentryFile.writeAsString(response.data ?? 'no response'); + + await transaction.finish(status: const SpanStatus.ok()); + } catch (exception, _) { + await transaction.finish(status: const SpanStatus.internalError()); + } +} + class ThemeProvider extends ChangeNotifier { ThemeData _theme = ThemeData.light(); diff --git a/flutter/example/pubspec.yaml b/flutter/example/pubspec.yaml index 6d9d3a2fa..9eb940f16 100644 --- a/flutter/example/pubspec.yaml +++ b/flutter/example/pubspec.yaml @@ -15,12 +15,14 @@ dependencies: sentry_flutter: sentry_dio: sentry_logging: + sentry_file: universal_platform: ^1.0.0 feedback: ^2.0.0 provider: ^6.0.0 dio: ^4.0.0 logging: ^1.0.0 package_info_plus: ^3.0.0 + path_provider: ^2.0.0 dev_dependencies: flutter_lints: ^2.0.0 diff --git a/flutter/example/pubspec_overrides.yaml b/flutter/example/pubspec_overrides.yaml index 832d30ee7..ec4b83d4f 100644 --- a/flutter/example/pubspec_overrides.yaml +++ b/flutter/example/pubspec_overrides.yaml @@ -7,3 +7,5 @@ dependency_overrides: path: ../../dio sentry_logging: path: ../../logging + sentry_file: + path: ../../file From de0ca3ce1b221815259ee23b887c47e6b0c88f07 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Tue, 6 Dec 2022 13:00:07 +0100 Subject: [PATCH 23/23] remove example --- flutter/example/lib/main.dart | 47 -------------------------- flutter/example/pubspec.yaml | 1 - flutter/example/pubspec_overrides.yaml | 2 -- 3 files changed, 50 deletions(-) diff --git a/flutter/example/lib/main.dart b/flutter/example/lib/main.dart index accd987e3..46665eadf 100644 --- a/flutter/example/lib/main.dart +++ b/flutter/example/lib/main.dart @@ -3,9 +3,6 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io' if (dart.library.html) 'dart:html'; -import 'package:path_provider/path_provider.dart'; - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -18,7 +15,6 @@ import 'user_feedback_dialog.dart'; import 'package:dio/dio.dart'; import 'package:sentry_dio/sentry_dio.dart'; import 'package:sentry_logging/sentry_logging.dart'; -import 'package:sentry_file/sentry_file.dart'; // ATTENTION: Change the DSN below with your own to see the events in Sentry. Get one at sentry.io const String _exampleDsn = @@ -343,12 +339,6 @@ class MainScaffold extends StatelessWidget { }, child: const Text('Capture User Feedback'), ), - ElevatedButton( - onPressed: () async { - await _manipulateFile(); - }, - child: const Text('Manipulate file'), - ), ElevatedButton( onPressed: () async { await showDialog( @@ -673,43 +663,6 @@ Future showDialogWithTextAndImage(BuildContext context) async { await transaction.finish(status: const SpanStatus.ok()); } -Future get _localPath async { - final directory = await getApplicationDocumentsDirectory(); - - return directory.path; -} - -Future get _localFile async { - final path = await _localPath; - return File('$path/response.txt'); -} - -Future _manipulateFile() async { - final transaction = Sentry.getSpan() ?? - Sentry.startTransaction( - 'MyFileExample', - 'file', - bindToScope: true, - ); - - final dio = Dio(); - dio.addSentry(captureFailedRequests: true); - - try { - final file = await _localFile; - final sentryFile = file.sentryTrace(); - if (!await sentryFile.exists()) { - await sentryFile.create(); - } - final response = await dio.get('https://flutter.dev/'); - await sentryFile.writeAsString(response.data ?? 'no response'); - - await transaction.finish(status: const SpanStatus.ok()); - } catch (exception, _) { - await transaction.finish(status: const SpanStatus.internalError()); - } -} - class ThemeProvider extends ChangeNotifier { ThemeData _theme = ThemeData.light(); diff --git a/flutter/example/pubspec.yaml b/flutter/example/pubspec.yaml index 9eb940f16..2f899397f 100644 --- a/flutter/example/pubspec.yaml +++ b/flutter/example/pubspec.yaml @@ -15,7 +15,6 @@ dependencies: sentry_flutter: sentry_dio: sentry_logging: - sentry_file: universal_platform: ^1.0.0 feedback: ^2.0.0 provider: ^6.0.0 diff --git a/flutter/example/pubspec_overrides.yaml b/flutter/example/pubspec_overrides.yaml index ec4b83d4f..832d30ee7 100644 --- a/flutter/example/pubspec_overrides.yaml +++ b/flutter/example/pubspec_overrides.yaml @@ -7,5 +7,3 @@ dependency_overrides: path: ../../dio sentry_logging: path: ../../logging - sentry_file: - path: ../../file