diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b0e394e82..99eef6e809 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Features +- SentryIOOverridesIntegration ([#1362](https://github.com/getsentry/sentry-dart/pull/1362)) - Add `enableTracing` option ([#1395](https://github.com/getsentry/sentry-dart/pull/1395)) - This change is backwards compatible. The default is `null` meaning existing behaviour remains unchanged (setting either `tracesSampleRate` or `tracesSampler` enables performance). - If set to `true`, performance is enabled, even if no `tracesSampleRate` or `tracesSampler` have been configured. diff --git a/file/lib/sentry_file.dart b/file/lib/sentry_file.dart index bd59fdea55..e5edf1c54a 100644 --- a/file/lib/sentry_file.dart +++ b/file/lib/sentry_file.dart @@ -1,2 +1,4 @@ export 'src/sentry_file.dart'; export 'src/sentry_file_extension.dart'; +export 'src/sentry_io_overrides_integration.dart'; +export 'src/sentry_io_overrides.dart'; diff --git a/file/lib/src/sentry_io_overrides.dart b/file/lib/src/sentry_io_overrides.dart new file mode 100644 index 0000000000..9b6231017e --- /dev/null +++ b/file/lib/src/sentry_io_overrides.dart @@ -0,0 +1,21 @@ +import 'dart:io'; +import 'package:sentry/sentry.dart'; + +import '../sentry_file.dart'; + +/// If set to [IOOverrides.global], newly created [File] instances will be of +/// type [SentryFile]. +/// Enable by adding [SentryIOOverridesIntegration] to [SentryOptions]. +class SentryIOOverrides extends IOOverrides { + final Hub _hub; + + SentryIOOverrides(this._hub); + + @override + File createFile(String path) { + return SentryFile( + super.createFile(path), + hub: _hub, + ); + } +} diff --git a/file/lib/src/sentry_io_overrides_integration.dart b/file/lib/src/sentry_io_overrides_integration.dart new file mode 100644 index 0000000000..dc22763a57 --- /dev/null +++ b/file/lib/src/sentry_io_overrides_integration.dart @@ -0,0 +1,35 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:sentry/sentry.dart'; +import 'sentry_io_overrides.dart'; + +/// When installed, every new file will be created as [SentryFile]. +/// When installed, operations will use [SentryFile] instead of dart:io's [File] +/// implementation whenever [File] is used. +/// +/// When closed, the [IOOverrides.current] value before this integration was +/// added will be assigned to [IOOverrides.global]. +class SentryIOOverridesIntegration extends Integration { + IOOverrides? _previousOverrides; + bool _installed = false; + + @override + FutureOr call(Hub hub, SentryOptions options) { + if (options.isTracingEnabled()) { + _previousOverrides = IOOverrides.current; + _installed = true; + IOOverrides.global = SentryIOOverrides(hub); + options.sdk.addIntegration('sentryIOOverridesIntegration'); + } + } + + @override + FutureOr close() { + if (_installed) { + IOOverrides.global = _previousOverrides; + _previousOverrides = null; + _installed = false; + } + } +} diff --git a/file/test/sentry_io_overrides_integration_test.dart b/file/test/sentry_io_overrides_integration_test.dart new file mode 100644 index 0000000000..86d5f25d74 --- /dev/null +++ b/file/test/sentry_io_overrides_integration_test.dart @@ -0,0 +1,77 @@ +import 'dart:io'; + +import 'package:sentry/sentry.dart'; +import 'package:sentry_file/sentry_file.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +import 'mock_sentry_client.dart'; + +void main() { + late IOOverrides? current; + late Fixture fixture; + + setUp(() { + current = IOOverrides.current; + fixture = Fixture(); + }); + + tearDown(() { + IOOverrides.global = current; + }); + + test('adding integration installs io overrides', () { + fixture.options.tracesSampleRate = 1.0; + + final sut = fixture.getSut(); + sut.call(fixture.hub, fixture.options); + + expect( + fixture.options.sdk.integrations.contains('sentryIOOverridesIntegration'), + isTrue, + ); + expect(IOOverrides.current is SentryIOOverrides, isTrue); + }); + + test('not installed when tracing disabled', () { + final sut = fixture.getSut(); + sut.call(fixture.hub, fixture.options); + + expect( + fixture.options.sdk.integrations.contains('sentryIOOverridesIntegration'), + isFalse, + ); + expect(IOOverrides.current is SentryIOOverrides, isFalse); + }); + + test('global overrides restored', () { + final previous = IOOverrides.current; + + fixture.options.tracesSampleRate = 1.0; + + final sut = fixture.getSut(); + sut.call(fixture.hub, fixture.options); + sut.close(); + + expect(IOOverrides.current, previous); + }); + + test('files created are sentry file after adding integration', () { + fixture.options.tracesSampleRate = 1.0; + + final sut = fixture.getSut(); + sut.call(fixture.hub, fixture.options); + + final file = File("/home"); + expect(file is SentryFile, true); + }); +} + +class Fixture { + final options = SentryOptions(dsn: fakeDsn); + late final hub = Hub(options); + + SentryIOOverridesIntegration getSut() { + return SentryIOOverridesIntegration(); + } +}