From 2ca35c5c9d5b7092a6e1a8ff892152af7655724f Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Thu, 14 Dec 2023 02:03:05 +0100 Subject: [PATCH 01/18] poc --- dart/lib/src/sentry_client.dart | 4 +++ dart/lib/src/sentry_options.dart | 6 ++++ .../transport/spotlight_http_transport.dart | 29 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 dart/lib/src/transport/spotlight_http_transport.dart diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index 62d2072b85..51d6dddf3c 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -16,6 +16,7 @@ import 'sentry_options.dart'; import 'sentry_stack_trace_factory.dart'; import 'transport/http_transport.dart'; import 'transport/noop_transport.dart'; +import 'transport/spotlight_http_transport.dart'; import 'utils/isolate_utils.dart'; import 'version.dart'; import 'sentry_envelope.dart'; @@ -49,6 +50,9 @@ class SentryClient { final rateLimiter = RateLimiter(options); options.transport = HttpTransport(options, rateLimiter); } + if (options.enableSpotlight) { + options.transport = SpotlightHttpTransport(options, options.transport); + } return SentryClient._(options); } diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 7d0d18622a..b57616e555 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -374,6 +374,12 @@ class SentryOptions { /// Settings this to `false` will set the `level` to [SentryLevel.error]. bool markAutomaticallyCollectedErrorsAsFatal = true; + /// Whether to enable Spotlight for local development. + bool enableSpotlight = false; + + /// The Spotlight URL. Defaults to http://localhost:8969/stream + String spotlightUrl = 'http://localhost:8969/stream'; + SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { platformChecker = checker; diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart new file mode 100644 index 0000000000..b50d04312e --- /dev/null +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -0,0 +1,29 @@ +import 'package:http/http.dart'; + +import '../../sentry.dart'; + +/// Spotlight HTTP transport class that sends Sentry envelopes to both Sentry and Spotlight. +class SpotlightHttpTransport extends Transport { + final SentryOptions _options; + final Transport _transport; + + SpotlightHttpTransport(this._options, this._transport); + + @override + Future send(SentryEnvelope envelope) async { + await _sendToSpotlight(envelope); + return _transport.send(envelope); + } + + Future _sendToSpotlight(SentryEnvelope envelope) async { + final Uri spotlightUri = Uri.parse(_options.spotlightUrl); + final StreamedRequest spotlightRequest = + StreamedRequest('POST', spotlightUri); + + try { + await _options.httpClient.send(spotlightRequest); + } catch (e) { + // Handle any exceptions. + } + } +} From 3a985bd3e5569c06e8f4f0b2065e25da57465f73 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Thu, 14 Dec 2023 16:57:26 +0100 Subject: [PATCH 02/18] update spotlight transport --- .../transport/spotlight_http_transport.dart | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index b50d04312e..6c2d9eb1ac 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -1,11 +1,14 @@ import 'package:http/http.dart'; import '../../sentry.dart'; +import '../client_reports/discard_reason.dart'; +import 'data_category.dart'; /// Spotlight HTTP transport class that sends Sentry envelopes to both Sentry and Spotlight. class SpotlightHttpTransport extends Transport { final SentryOptions _options; final Transport _transport; + final Map _headers = {'Content-Type': 'application/x-sentry-envelope'}; SpotlightHttpTransport(this._options, this._transport); @@ -20,10 +23,38 @@ class SpotlightHttpTransport extends Transport { final StreamedRequest spotlightRequest = StreamedRequest('POST', spotlightUri); - try { - await _options.httpClient.send(spotlightRequest); - } catch (e) { - // Handle any exceptions. + envelope + .envelopeStream(_options) + .listen(spotlightRequest.sink.add) + .onDone(spotlightRequest.sink.close); + + spotlightRequest.headers.addAll(_headers); + + final response = await _options.httpClient + .send(spotlightRequest) + .then(Response.fromStream); + + if (response.statusCode != 200) { + // body guard to not log the error as it has performance impact to allocate + // the body String. + if (_options.debug) { + _options.logger( + SentryLevel.error, + 'Spotlight Sidecar API returned an error, statusCode = ${response.statusCode}, ' + 'body = ${response.body}', + ); + print('body = ${response.request}'); + } + + if (response.statusCode >= 400 && response.statusCode != 429) { + _options.recorder.recordLostEvent( + DiscardReason.networkError, DataCategory.error); + } + } else { + _options.logger( + SentryLevel.debug, + 'Envelope ${envelope.header.eventId ?? "--"} was sent successfully to spotlight ($spotlightUri)', + ); } } } From 52e500e9367d87b072c71d8c3de0567b0b9fb08a Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 15 Dec 2023 12:57:13 +0100 Subject: [PATCH 03/18] update --- dart/lib/src/sentry_options.dart | 2 +- dart/lib/src/transport/http_transport.dart | 88 +---------------- .../http_transport_request_creator.dart | 95 +++++++++++++++++++ .../transport/spotlight_http_transport.dart | 39 +++++--- 4 files changed, 125 insertions(+), 99 deletions(-) create mode 100644 dart/lib/src/transport/http_transport_request_creator.dart diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index b57616e555..aa40e132c4 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -378,7 +378,7 @@ class SentryOptions { bool enableSpotlight = false; /// The Spotlight URL. Defaults to http://localhost:8969/stream - String spotlightUrl = 'http://localhost:8969/stream'; + String spotlightUrl = 'http://10.0.2.2:8969/stream'; SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index acf0e6cf64..af4f1d82af 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -2,11 +2,11 @@ import 'dart:async'; import 'dart:convert'; import 'package:http/http.dart'; +import 'http_transport_request_creator.dart'; import '../client_reports/client_report_recorder.dart'; import '../client_reports/discard_reason.dart'; import 'data_category.dart'; -import 'noop_encode.dart' if (dart.library.io) 'encode.dart'; import '../noop_client.dart'; import '../protocol.dart'; import '../sentry_options.dart'; @@ -24,9 +24,7 @@ class HttpTransport implements Transport { final ClientReportRecorder _recorder; - late _CredentialBuilder _credentialBuilder; - - final Map _headers; + late HttpTransportRequestCreator _httpTransportRequestCreator; factory HttpTransport(SentryOptions options, RateLimiter rateLimiter) { if (options.httpClient is NoOpClient) { @@ -38,15 +36,8 @@ class HttpTransport implements Transport { HttpTransport._(this._options, this._rateLimiter) : _dsn = Dsn.parse(_options.dsn!), - _recorder = _options.recorder, - _headers = _buildHeaders( - _options.platformChecker.isWeb, - _options.sentryClientName, - ) { - _credentialBuilder = _CredentialBuilder( - _dsn, - _options.sentryClientName, - ); + _recorder = _options.recorder { + _httpTransportRequestCreator = HttpTransportRequestCreator(_options, _dsn.postUri); } @override @@ -57,7 +48,7 @@ class HttpTransport implements Transport { } filteredEnvelope.header.sentAt = _options.clock(); - final streamedRequest = await _createStreamedRequest(filteredEnvelope); + final streamedRequest = await _httpTransportRequestCreator.createRequest(filteredEnvelope); final response = await _options.httpClient .send(streamedRequest) .then(Response.fromStream); @@ -95,27 +86,6 @@ class HttpTransport implements Transport { return SentryId.fromId(eventId); } - Future _createStreamedRequest( - SentryEnvelope envelope) async { - final streamedRequest = StreamedRequest('POST', _dsn.postUri); - - if (_options.compressPayload) { - final compressionSink = compressInSink(streamedRequest.sink, _headers); - envelope - .envelopeStream(_options) - .listen(compressionSink.add) - .onDone(compressionSink.close); - } else { - envelope - .envelopeStream(_options) - .listen(streamedRequest.sink.add) - .onDone(streamedRequest.sink.close); - } - streamedRequest.headers.addAll(_credentialBuilder.configure(_headers)); - - return streamedRequest; - } - void _updateRetryAfterLimits(Response response) { // seconds final retryAfterHeader = response.headers['Retry-After']; @@ -131,51 +101,3 @@ class HttpTransport implements Transport { sentryRateLimitHeader, retryAfterHeader, response.statusCode); } } - -class _CredentialBuilder { - final String _authHeader; - - _CredentialBuilder._(String authHeader) : _authHeader = authHeader; - - factory _CredentialBuilder(Dsn dsn, String sdkIdentifier) { - final authHeader = _buildAuthHeader( - publicKey: dsn.publicKey, - secretKey: dsn.secretKey, - sdkIdentifier: sdkIdentifier, - ); - - return _CredentialBuilder._(authHeader); - } - - static String _buildAuthHeader({ - required String publicKey, - String? secretKey, - required String sdkIdentifier, - }) { - var header = 'Sentry sentry_version=7, sentry_client=$sdkIdentifier, ' - 'sentry_key=$publicKey'; - - if (secretKey != null) { - header += ', sentry_secret=$secretKey'; - } - - return header; - } - - Map configure(Map headers) { - return headers - ..addAll( - {'X-Sentry-Auth': _authHeader}, - ); - } -} - -Map _buildHeaders(bool isWeb, String sdkIdentifier) { - final headers = {'Content-Type': 'application/x-sentry-envelope'}; - // NOTE(lejard_h) overriding user agent on VM and Flutter not sure why - // for web it use browser user agent - if (!isWeb) { - headers['User-Agent'] = sdkIdentifier; - } - return headers; -} diff --git a/dart/lib/src/transport/http_transport_request_creator.dart b/dart/lib/src/transport/http_transport_request_creator.dart new file mode 100644 index 0000000000..6390c3b908 --- /dev/null +++ b/dart/lib/src/transport/http_transport_request_creator.dart @@ -0,0 +1,95 @@ +import 'package:http/http.dart'; +import 'package:meta/meta.dart'; + +import '../../sentry.dart'; +import 'encode.dart'; + +@internal +class HttpTransportRequestCreator { + final SentryOptions _options; + final Dsn _dsn; + final Map _headers; + final Uri _requestUri; + late _CredentialBuilder _credentialBuilder; + + HttpTransportRequestCreator(this._options, this._requestUri) + : _dsn = Dsn.parse(_options.dsn!), + _headers = _buildHeaders( + _options.platformChecker.isWeb, + _options.sentryClientName, + ) { + _credentialBuilder = _CredentialBuilder( + _dsn, + _options.sentryClientName, + ); + } + + Future createRequest(SentryEnvelope envelope) async { + final streamedRequest = StreamedRequest('POST', _requestUri); + + if (_options.compressPayload) { + final compressionSink = + compressInSink(streamedRequest.sink, _headers); + envelope + .envelopeStream(_options) + .listen(compressionSink.add) + .onDone(compressionSink.close); + } else { + envelope + .envelopeStream(_options) + .listen(streamedRequest.sink.add) + .onDone(streamedRequest.sink.close); + } + + streamedRequest.headers.addAll(_credentialBuilder.configure(_headers)); + return streamedRequest; + } +} + +Map _buildHeaders(bool isWeb, String sdkIdentifier) { + final headers = {'Content-Type': 'application/x-sentry-envelope'}; + // NOTE(lejard_h) overriding user agent on VM and Flutter not sure why + // for web it use browser user agent + if (!isWeb) { + headers['User-Agent'] = sdkIdentifier; + } + return headers; +} + +class _CredentialBuilder { + final String _authHeader; + + _CredentialBuilder._(String authHeader) : _authHeader = authHeader; + + factory _CredentialBuilder(Dsn dsn, String sdkIdentifier) { + final authHeader = _buildAuthHeader( + publicKey: dsn.publicKey, + secretKey: dsn.secretKey, + sdkIdentifier: sdkIdentifier, + ); + + return _CredentialBuilder._(authHeader); + } + + static String _buildAuthHeader({ + required String publicKey, + String? secretKey, + required String sdkIdentifier, + }) { + var header = 'Sentry sentry_version=7, sentry_client=$sdkIdentifier, ' + 'sentry_key=$publicKey'; + + if (secretKey != null) { + header += ', sentry_secret=$secretKey'; + } + + return header; + } + + Map configure(Map headers) { + return headers + ..addAll( + {'X-Sentry-Auth': _authHeader}, + ); + } +} diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index 6c2d9eb1ac..34185f992a 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -1,16 +1,28 @@ import 'package:http/http.dart'; +import 'http_transport_request_creator.dart'; import '../../sentry.dart'; import '../client_reports/discard_reason.dart'; +import '../noop_client.dart'; import 'data_category.dart'; -/// Spotlight HTTP transport class that sends Sentry envelopes to both Sentry and Spotlight. +/// Spotlight HTTP transport decorator that sends Sentry envelopes to both Sentry and Spotlight. class SpotlightHttpTransport extends Transport { final SentryOptions _options; final Transport _transport; - final Map _headers = {'Content-Type': 'application/x-sentry-envelope'}; + final HttpTransportRequestCreator _requestCreator; + + factory SpotlightHttpTransport(SentryOptions options, Transport transport) { + if (options.httpClient is NoOpClient) { + options.httpClient = Client(); + } + return SpotlightHttpTransport._(options, transport); + } + + SpotlightHttpTransport._(this._options, this._transport) : + _requestCreator = + HttpTransportRequestCreator(_options, Uri.parse(_options.spotlightUrl)); - SpotlightHttpTransport(this._options, this._transport); @override Future send(SentryEnvelope envelope) async { @@ -19,16 +31,13 @@ class SpotlightHttpTransport extends Transport { } Future _sendToSpotlight(SentryEnvelope envelope) async { - final Uri spotlightUri = Uri.parse(_options.spotlightUrl); - final StreamedRequest spotlightRequest = - StreamedRequest('POST', spotlightUri); + envelope.header.sentAt = _options.clock(); - envelope - .envelopeStream(_options) - .listen(spotlightRequest.sink.add) - .onDone(spotlightRequest.sink.close); + // Screenshots do not work currently https://github.com/getsentry/spotlight/issues/274 + envelope.items + .removeWhere((element) => element.header.contentType == 'image/png'); - spotlightRequest.headers.addAll(_headers); + final spotlightRequest = await _requestCreator.createRequest(envelope); final response = await _options.httpClient .send(spotlightRequest) @@ -40,20 +49,20 @@ class SpotlightHttpTransport extends Transport { if (_options.debug) { _options.logger( SentryLevel.error, - 'Spotlight Sidecar API returned an error, statusCode = ${response.statusCode}, ' + 'Spotlight returned an error, statusCode = ${response.statusCode}, ' 'body = ${response.body}', ); print('body = ${response.request}'); } if (response.statusCode >= 400 && response.statusCode != 429) { - _options.recorder.recordLostEvent( - DiscardReason.networkError, DataCategory.error); + _options.recorder + .recordLostEvent(DiscardReason.networkError, DataCategory.error); } } else { _options.logger( SentryLevel.debug, - 'Envelope ${envelope.header.eventId ?? "--"} was sent successfully to spotlight ($spotlightUri)', + 'Envelope ${envelope.header.eventId ?? "--"} was sent successfully to Spotlight (${_options.spotlightUrl})', ); } } From 203da9c065af23dbb359e69a401f2fa82a83e4aa Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 15 Dec 2023 13:34:58 +0100 Subject: [PATCH 04/18] Add test --- dart/lib/src/transport/http_transport.dart | 7 +- .../http_transport_request_creator.dart | 3 +- .../transport/spotlight_http_transport.dart | 8 +-- .../spotlight_http_transport_test.dart | 70 +++++++++++++++++++ 4 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 dart/test/transport/spotlight_http_transport_test.dart diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index af4f1d82af..6e214b56df 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -37,7 +37,8 @@ class HttpTransport implements Transport { HttpTransport._(this._options, this._rateLimiter) : _dsn = Dsn.parse(_options.dsn!), _recorder = _options.recorder { - _httpTransportRequestCreator = HttpTransportRequestCreator(_options, _dsn.postUri); + _httpTransportRequestCreator = + HttpTransportRequestCreator(_options, _dsn.postUri); } @override @@ -48,7 +49,9 @@ class HttpTransport implements Transport { } filteredEnvelope.header.sentAt = _options.clock(); - final streamedRequest = await _httpTransportRequestCreator.createRequest(filteredEnvelope); + final streamedRequest = + await _httpTransportRequestCreator.createRequest(filteredEnvelope); + final response = await _options.httpClient .send(streamedRequest) .then(Response.fromStream); diff --git a/dart/lib/src/transport/http_transport_request_creator.dart b/dart/lib/src/transport/http_transport_request_creator.dart index 6390c3b908..49064419f8 100644 --- a/dart/lib/src/transport/http_transport_request_creator.dart +++ b/dart/lib/src/transport/http_transport_request_creator.dart @@ -28,8 +28,7 @@ class HttpTransportRequestCreator { final streamedRequest = StreamedRequest('POST', _requestUri); if (_options.compressPayload) { - final compressionSink = - compressInSink(streamedRequest.sink, _headers); + final compressionSink = compressInSink(streamedRequest.sink, _headers); envelope .envelopeStream(_options) .listen(compressionSink.add) diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index 34185f992a..bb037d15d8 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -19,10 +19,9 @@ class SpotlightHttpTransport extends Transport { return SpotlightHttpTransport._(options, transport); } - SpotlightHttpTransport._(this._options, this._transport) : - _requestCreator = - HttpTransportRequestCreator(_options, Uri.parse(_options.spotlightUrl)); - + SpotlightHttpTransport._(this._options, this._transport) + : _requestCreator = HttpTransportRequestCreator( + _options, Uri.parse(_options.spotlightUrl)); @override Future send(SentryEnvelope envelope) async { @@ -52,7 +51,6 @@ class SpotlightHttpTransport extends Transport { 'Spotlight returned an error, statusCode = ${response.statusCode}, ' 'body = ${response.body}', ); - print('body = ${response.request}'); } if (response.statusCode >= 400 && response.statusCode != 429) { diff --git a/dart/test/transport/spotlight_http_transport_test.dart b/dart/test/transport/spotlight_http_transport_test.dart new file mode 100644 index 0000000000..0c70874114 --- /dev/null +++ b/dart/test/transport/spotlight_http_transport_test.dart @@ -0,0 +1,70 @@ +import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/transport/http_transport.dart'; +import 'package:sentry/src/transport/rate_limiter.dart'; +import 'package:sentry/src/transport/spotlight_http_transport.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +import '../mocks.dart'; +import '../mocks/mock_client_report_recorder.dart'; + +void main() { + group('send to Sentry', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('send event to Sentry even if Spotlight fails', () async { + List? body; + + final httpMock = MockClient((http.Request request) async { + body = request.bodyBytes; + if (request.url.toString() == fixture.options.spotlightUrl) { + return http.Response('{}', 500); + } + return http.Response('{}', 200); + }); + + fixture.options.compressPayload = false; + final mockRateLimiter = MockRateLimiter(); + final sut = fixture.getSut(httpMock, mockRateLimiter); + + final sentryEvent = SentryEvent(); + final envelope = SentryEnvelope.fromEvent( + sentryEvent, + fixture.options.sdk, + dsn: fixture.options.dsn, + ); + await sut.send(envelope); + + final envelopeData = []; + await envelope + .envelopeStream(fixture.options) + .forEach(envelopeData.addAll); + + expect(body, envelopeData); + }); + }); +} + +class Fixture { + final options = SentryOptions( + dsn: 'https://public:secret@sentry.example.com/1', + ); + + late var clientReportRecorder = MockClientReportRecorder(); + + Transport getSut(http.Client client, RateLimiter rateLimiter) { + options.httpClient = client; + options.recorder = clientReportRecorder; + options.clock = () { + return DateTime.utc(2019); + }; + final httpTransport = HttpTransport(options, rateLimiter); + return SpotlightHttpTransport(options, httpTransport); + } +} From dd334dcde22249edd8e0abbfebc98a4458eed690 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 15 Dec 2023 13:37:43 +0100 Subject: [PATCH 05/18] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c983f6680..a05538f1a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Features +- Add [Spotlight](https://spotlightjs.com/about/) support ([#1786](https://github.com/getsentry/sentry-dart/pull/1786)) - Add option to opt out of fatal level for automatically collected errors ([#1738](https://github.com/getsentry/sentry-dart/pull/1738)) - Add `Hive` breadcrumbs ([#1773](https://github.com/getsentry/sentry-dart/pull/1773)) From 00dba0da2f12580c8aecdcf9cdfaee2b3d4e9bfb Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 15 Dec 2023 13:47:18 +0100 Subject: [PATCH 06/18] update --- dart/lib/src/transport/spotlight_http_transport.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index bb037d15d8..e2f74c848f 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -43,8 +43,6 @@ class SpotlightHttpTransport extends Transport { .then(Response.fromStream); if (response.statusCode != 200) { - // body guard to not log the error as it has performance impact to allocate - // the body String. if (_options.debug) { _options.logger( SentryLevel.error, From 574550ea9377449ac4ae3106b6b100b4b461dcdf Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 15 Dec 2023 14:03:50 +0100 Subject: [PATCH 07/18] fix --- dart/test/environment_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dart/test/environment_test.dart b/dart/test/environment_test.dart index e4bf97fea7..b16225d1dd 100644 --- a/dart/test/environment_test.dart +++ b/dart/test/environment_test.dart @@ -39,7 +39,7 @@ void main() { test('SentryOptions are overriden by environment', () async { final options = SentryOptions(); options.environmentVariables = MockEnvironmentVariables( - dsn: 'foo-bar', + dsn: fakeDsn, environment: 'staging', release: 'release-9.8.7', dist: 'bar', @@ -51,7 +51,7 @@ void main() { options: options, ); - expect(options.dsn, 'foo-bar'); + expect(options.dsn, fakeDsn); expect(options.environment, 'staging'); expect(options.release, 'release-9.8.7'); expect(options.dist, 'bar'); From 44ea944af92cebf6d41a8239d2828f8d6fb029d1 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 15 Dec 2023 16:29:22 +0100 Subject: [PATCH 08/18] update --- dart/lib/src/transport/http_transport.dart | 57 ++++++------------- ...rt => http_transport_request_handler.dart} | 12 ++-- .../transport/spotlight_http_transport.dart | 32 +++-------- dart/lib/src/utils/transport_utils.dart | 30 ++++++++++ 4 files changed, 63 insertions(+), 68 deletions(-) rename dart/lib/src/transport/{http_transport_request_creator.dart => http_transport_request_handler.dart} (89%) create mode 100644 dart/lib/src/utils/transport_utils.dart diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index 6e214b56df..1041ba0fa0 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -2,11 +2,9 @@ import 'dart:async'; import 'dart:convert'; import 'package:http/http.dart'; -import 'http_transport_request_creator.dart'; +import '../utils/transport_utils.dart'; +import 'http_transport_request_handler.dart'; -import '../client_reports/client_report_recorder.dart'; -import '../client_reports/discard_reason.dart'; -import 'data_category.dart'; import '../noop_client.dart'; import '../protocol.dart'; import '../sentry_options.dart'; @@ -18,13 +16,9 @@ import 'rate_limiter.dart'; class HttpTransport implements Transport { final SentryOptions _options; - final Dsn _dsn; - final RateLimiter _rateLimiter; - final ClientReportRecorder _recorder; - - late HttpTransportRequestCreator _httpTransportRequestCreator; + late HttpTransportRequestHandler _requestHandler; factory HttpTransport(SentryOptions options, RateLimiter rateLimiter) { if (options.httpClient is NoOpClient) { @@ -34,11 +28,9 @@ class HttpTransport implements Transport { return HttpTransport._(options, rateLimiter); } - HttpTransport._(this._options, this._rateLimiter) - : _dsn = Dsn.parse(_options.dsn!), - _recorder = _options.recorder { - _httpTransportRequestCreator = - HttpTransportRequestCreator(_options, _dsn.postUri); + HttpTransport._(this._options, this._rateLimiter) { + final dsn = Dsn.parse(_options.dsn!); + _requestHandler = HttpTransportRequestHandler(_options, dsn.postUri); } @override @@ -50,7 +42,7 @@ class HttpTransport implements Transport { filteredEnvelope.header.sentAt = _options.clock(); final streamedRequest = - await _httpTransportRequestCreator.createRequest(filteredEnvelope); + await _requestHandler.createRequest(filteredEnvelope); final response = await _options.httpClient .send(streamedRequest) @@ -58,35 +50,22 @@ class HttpTransport implements Transport { _updateRetryAfterLimits(response); - if (response.statusCode != 200) { - // body guard to not log the error as it has performance impact to allocate - // the body String. - if (_options.debug) { - _options.logger( - SentryLevel.error, - 'API returned an error, statusCode = ${response.statusCode}, ' - 'body = ${response.body}', - ); - } - - if (response.statusCode >= 400 && response.statusCode != 429) { - _recorder.recordLostEvent( - DiscardReason.networkError, DataCategory.error); - } + TransportUtils.logResponse(_options, envelope, response, target: 'Sentry'); - return SentryId.empty(); - } else { - _options.logger( - SentryLevel.debug, - 'Envelope ${envelope.header.eventId ?? "--"} was sent successfully.', - ); + if (response.statusCode == 200) { + return _parseEventId(response); } + return SentryId.empty(); + } - final eventId = json.decode(response.body)['id']; - if (eventId == null) { + SentryId? _parseEventId(Response response) { + try { + final eventId = json.decode(response.body)['id']; + return eventId != null ? SentryId.fromId(eventId) : null; + } catch (e) { + _options.logger(SentryLevel.error, 'Error parsing response: $e'); return null; } - return SentryId.fromId(eventId); } void _updateRetryAfterLimits(Response response) { diff --git a/dart/lib/src/transport/http_transport_request_creator.dart b/dart/lib/src/transport/http_transport_request_handler.dart similarity index 89% rename from dart/lib/src/transport/http_transport_request_creator.dart rename to dart/lib/src/transport/http_transport_request_handler.dart index 49064419f8..4aa50898c5 100644 --- a/dart/lib/src/transport/http_transport_request_creator.dart +++ b/dart/lib/src/transport/http_transport_request_handler.dart @@ -1,18 +1,22 @@ +import 'dart:async'; + import 'package:http/http.dart'; import 'package:meta/meta.dart'; -import '../../sentry.dart'; -import 'encode.dart'; +import 'noop_encode.dart' if (dart.library.io) 'encode.dart'; +import '../protocol.dart'; +import '../sentry_options.dart'; +import '../sentry_envelope.dart'; @internal -class HttpTransportRequestCreator { +class HttpTransportRequestHandler { final SentryOptions _options; final Dsn _dsn; final Map _headers; final Uri _requestUri; late _CredentialBuilder _credentialBuilder; - HttpTransportRequestCreator(this._options, this._requestUri) + HttpTransportRequestHandler(this._options, this._requestUri) : _dsn = Dsn.parse(_options.dsn!), _headers = _buildHeaders( _options.platformChecker.isWeb, diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index e2f74c848f..3d0ef0c7b1 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -1,16 +1,15 @@ import 'package:http/http.dart'; -import 'http_transport_request_creator.dart'; +import '../utils/transport_utils.dart'; +import 'http_transport_request_handler.dart'; import '../../sentry.dart'; -import '../client_reports/discard_reason.dart'; import '../noop_client.dart'; -import 'data_category.dart'; /// Spotlight HTTP transport decorator that sends Sentry envelopes to both Sentry and Spotlight. class SpotlightHttpTransport extends Transport { final SentryOptions _options; final Transport _transport; - final HttpTransportRequestCreator _requestCreator; + final HttpTransportRequestHandler _requestHandler; factory SpotlightHttpTransport(SentryOptions options, Transport transport) { if (options.httpClient is NoOpClient) { @@ -20,7 +19,7 @@ class SpotlightHttpTransport extends Transport { } SpotlightHttpTransport._(this._options, this._transport) - : _requestCreator = HttpTransportRequestCreator( + : _requestHandler = HttpTransportRequestHandler( _options, Uri.parse(_options.spotlightUrl)); @override @@ -36,30 +35,13 @@ class SpotlightHttpTransport extends Transport { envelope.items .removeWhere((element) => element.header.contentType == 'image/png'); - final spotlightRequest = await _requestCreator.createRequest(envelope); + final spotlightRequest = await _requestHandler.createRequest(envelope); final response = await _options.httpClient .send(spotlightRequest) .then(Response.fromStream); - if (response.statusCode != 200) { - if (_options.debug) { - _options.logger( - SentryLevel.error, - 'Spotlight returned an error, statusCode = ${response.statusCode}, ' - 'body = ${response.body}', - ); - } - - if (response.statusCode >= 400 && response.statusCode != 429) { - _options.recorder - .recordLostEvent(DiscardReason.networkError, DataCategory.error); - } - } else { - _options.logger( - SentryLevel.debug, - 'Envelope ${envelope.header.eventId ?? "--"} was sent successfully to Spotlight (${_options.spotlightUrl})', - ); - } + TransportUtils.logResponse(_options, envelope, response, + target: 'Spotlight'); } } diff --git a/dart/lib/src/utils/transport_utils.dart b/dart/lib/src/utils/transport_utils.dart new file mode 100644 index 0000000000..388db8e8d5 --- /dev/null +++ b/dart/lib/src/utils/transport_utils.dart @@ -0,0 +1,30 @@ +import 'package:http/http.dart'; + +import '../../sentry_io.dart'; +import '../client_reports/discard_reason.dart'; +import '../transport/data_category.dart'; + +class TransportUtils { + static void logResponse( + SentryOptions options, SentryEnvelope envelope, Response response, + {required String target}) { + if (response.statusCode != 200) { + if (options.debug) { + options.logger( + SentryLevel.error, + 'Error, statusCode = ${response.statusCode}, body = ${response.body}', + ); + } + + if (response.statusCode >= 400 && response.statusCode != 429) { + options.recorder + .recordLostEvent(DiscardReason.networkError, DataCategory.error); + } + } else { + options.logger( + SentryLevel.debug, + 'Envelope ${envelope.header.eventId ?? "--"} was sent successfully to $target.', + ); + } + } +} From b93288a1e3e6a2fdfbc8b3d1ca473b64542c044a Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 15 Dec 2023 16:35:16 +0100 Subject: [PATCH 09/18] change late to final --- dart/lib/src/transport/http_transport.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index 1041ba0fa0..90dd8949ce 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -18,7 +18,7 @@ class HttpTransport implements Transport { final RateLimiter _rateLimiter; - late HttpTransportRequestHandler _requestHandler; + final HttpTransportRequestHandler _requestHandler; factory HttpTransport(SentryOptions options, RateLimiter rateLimiter) { if (options.httpClient is NoOpClient) { @@ -28,10 +28,9 @@ class HttpTransport implements Transport { return HttpTransport._(options, rateLimiter); } - HttpTransport._(this._options, this._rateLimiter) { - final dsn = Dsn.parse(_options.dsn!); - _requestHandler = HttpTransportRequestHandler(_options, dsn.postUri); - } + HttpTransport._(this._options, this._rateLimiter) + : _requestHandler = HttpTransportRequestHandler( + _options, Dsn.parse(_options.dsn!).postUri); @override Future send(SentryEnvelope envelope) async { From a77e5bd5cb885c3964c427172f378b71a86bdbb7 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 18 Dec 2023 12:11:36 +0100 Subject: [PATCH 10/18] Update --- dart/lib/src/sentry_options.dart | 7 +++++-- dart/lib/src/transport/spotlight_http_transport.dart | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index aa40e132c4..8bccb7c75a 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:developer'; +import 'dart:io'; import 'package:meta/meta.dart'; import 'package:http/http.dart'; @@ -377,8 +378,10 @@ class SentryOptions { /// Whether to enable Spotlight for local development. bool enableSpotlight = false; - /// The Spotlight URL. Defaults to http://localhost:8969/stream - String spotlightUrl = 'http://10.0.2.2:8969/stream'; + /// The Spotlight URL. + /// Defaults to http://10.0.2.2:8969/stream due to Emulator on Android. + /// Otherwise defaults to http://localhost:8969/stream. + String spotlightUrl = Platform.isAndroid ? 'http://10.0.2.2:8969/stream' : 'http://localhost:8969/stream'; SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index 3d0ef0c7b1..b7f0f159eb 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:http/http.dart'; import '../utils/transport_utils.dart'; import 'http_transport_request_handler.dart'; @@ -24,7 +26,14 @@ class SpotlightHttpTransport extends Transport { @override Future send(SentryEnvelope envelope) async { - await _sendToSpotlight(envelope); + print(_options.spotlightUrl); + try { + await _sendToSpotlight(envelope); + } catch (e) { + print('not here'); + _options.logger( + SentryLevel.warning, 'Failed to send envelope to Spotlight: $e'); + } return _transport.send(envelope); } From e97dce8871d3fc8f3292835320639a113df26e81 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 18 Dec 2023 12:12:46 +0100 Subject: [PATCH 11/18] Fix analyze --- dart/lib/src/transport/spotlight_http_transport.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index b7f0f159eb..909cba5626 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:http/http.dart'; import '../utils/transport_utils.dart'; import 'http_transport_request_handler.dart'; @@ -26,11 +24,9 @@ class SpotlightHttpTransport extends Transport { @override Future send(SentryEnvelope envelope) async { - print(_options.spotlightUrl); try { await _sendToSpotlight(envelope); } catch (e) { - print('not here'); _options.logger( SentryLevel.warning, 'Failed to send envelope to Spotlight: $e'); } From 8e527ba0f7b7245ce7bb29aa5946f44f3f776e08 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 18 Dec 2023 12:15:44 +0100 Subject: [PATCH 12/18] Add format --- dart/lib/src/sentry_options.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 8bccb7c75a..d36f1dbfaf 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -381,7 +381,9 @@ class SentryOptions { /// The Spotlight URL. /// Defaults to http://10.0.2.2:8969/stream due to Emulator on Android. /// Otherwise defaults to http://localhost:8969/stream. - String spotlightUrl = Platform.isAndroid ? 'http://10.0.2.2:8969/stream' : 'http://localhost:8969/stream'; + String spotlightUrl = Platform.isAndroid + ? 'http://10.0.2.2:8969/stream' + : 'http://localhost:8969/stream'; SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { From e864406b1d86713aed994bf250919c9aa53ed873 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 18 Dec 2023 12:25:06 +0100 Subject: [PATCH 13/18] Fix tests --- dart/lib/src/sentry_options.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index d36f1dbfaf..4078da3255 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -381,7 +381,7 @@ class SentryOptions { /// The Spotlight URL. /// Defaults to http://10.0.2.2:8969/stream due to Emulator on Android. /// Otherwise defaults to http://localhost:8969/stream. - String spotlightUrl = Platform.isAndroid + String spotlightUrl = PlatformChecker().platform.isAndroid ? 'http://10.0.2.2:8969/stream' : 'http://localhost:8969/stream'; From 6784f06aca40e21c214d1e8778deb3c2d468ce50 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 18 Dec 2023 15:28:25 +0100 Subject: [PATCH 14/18] change to Spotlight class --- dart/lib/sentry.dart | 2 ++ dart/lib/src/sentry_client.dart | 2 +- dart/lib/src/sentry_options.dart | 16 ++++++-------- dart/lib/src/spotlight.dart | 21 +++++++++++++++++++ .../transport/spotlight_http_transport.dart | 2 +- .../spotlight_http_transport_test.dart | 2 +- 6 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 dart/lib/src/spotlight.dart diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index 9d06bb7e2a..d8774f88a6 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -48,3 +48,5 @@ export 'src/utils/http_header_utils.dart'; export 'src/sentry_trace_origins.dart'; // ignore: invalid_export_of_internal_element export 'src/utils.dart'; +// spotlight debugging +export 'src/spotlight.dart'; diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index 51d6dddf3c..709bda104f 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -50,7 +50,7 @@ class SentryClient { final rateLimiter = RateLimiter(options); options.transport = HttpTransport(options, rateLimiter); } - if (options.enableSpotlight) { + if (options.spotlight.enabled) { options.transport = SpotlightHttpTransport(options, options.transport); } return SentryClient._(options); diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 4078da3255..918a5d5758 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:developer'; -import 'dart:io'; import 'package:meta/meta.dart'; import 'package:http/http.dart'; @@ -375,15 +374,12 @@ class SentryOptions { /// Settings this to `false` will set the `level` to [SentryLevel.error]. bool markAutomaticallyCollectedErrorsAsFatal = true; - /// Whether to enable Spotlight for local development. - bool enableSpotlight = false; - - /// The Spotlight URL. - /// Defaults to http://10.0.2.2:8969/stream due to Emulator on Android. - /// Otherwise defaults to http://localhost:8969/stream. - String spotlightUrl = PlatformChecker().platform.isAndroid - ? 'http://10.0.2.2:8969/stream' - : 'http://localhost:8969/stream'; + /// The Spotlight configuration. + /// Disabled by default. + /// ```dart + /// spotlight = Spotlight(enabled: true) + /// ``` + Spotlight spotlight = Spotlight(enabled: false); SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { diff --git a/dart/lib/src/spotlight.dart b/dart/lib/src/spotlight.dart new file mode 100644 index 0000000000..b106ed3547 --- /dev/null +++ b/dart/lib/src/spotlight.dart @@ -0,0 +1,21 @@ +import 'platform_checker.dart'; + +/// Spotlight configuration class. +class Spotlight { + /// Whether to enable Spotlight for local development. + bool enabled; + + /// The Spotlight Sidecar URL. + /// Defaults to http://10.0.2.2:8969/stream due to Emulator on Android. + /// Otherwise defaults to http://localhost:8969/stream. + String url; + + Spotlight({required this.enabled, String? url}) + : url = url ?? _defaultSpotlightUrl(); +} + +String _defaultSpotlightUrl() { + return (PlatformChecker().platform.isAndroid + ? 'http://10.0.2.2:8969/stream' + : 'http://localhost:8969/stream'); +} diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index 909cba5626..f51e77d478 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -20,7 +20,7 @@ class SpotlightHttpTransport extends Transport { SpotlightHttpTransport._(this._options, this._transport) : _requestHandler = HttpTransportRequestHandler( - _options, Uri.parse(_options.spotlightUrl)); + _options, Uri.parse(_options.spotlight.url)); @override Future send(SentryEnvelope envelope) async { diff --git a/dart/test/transport/spotlight_http_transport_test.dart b/dart/test/transport/spotlight_http_transport_test.dart index 0c70874114..b23f1fd87f 100644 --- a/dart/test/transport/spotlight_http_transport_test.dart +++ b/dart/test/transport/spotlight_http_transport_test.dart @@ -23,7 +23,7 @@ void main() { final httpMock = MockClient((http.Request request) async { body = request.bodyBytes; - if (request.url.toString() == fixture.options.spotlightUrl) { + if (request.url.toString() == fixture.options.spotlight.url) { return http.Response('{}', 500); } return http.Response('{}', 200); From 4ee46f792b13b31da91b959fd0364fb7fc4c658c Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 22 Dec 2023 02:45:52 +0100 Subject: [PATCH 15/18] add tests --- dart/test/sentry_client_test.dart | 8 ++++++++ dart/test/sentry_options_test.dart | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index cdbbd73950..ef2e1b1ac8 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -12,6 +12,7 @@ import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_stack_trace_factory.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:sentry/src/transport/data_category.dart'; +import 'package:sentry/src/transport/spotlight_http_transport.dart'; import 'package:test/test.dart'; import 'mocks.dart'; @@ -1706,6 +1707,13 @@ void main() { expect(capturedEnvelope.header.dsn, fixture.options.dsn); }); + + test('Spotlight enabled should set transport to SpotlightHttpTransport', () async { + fixture.options.spotlight = Spotlight(enabled: true); + fixture.getSut(); + + expect(fixture.options.transport is SpotlightHttpTransport, true); + }); }); } diff --git a/dart/test/sentry_options_test.dart b/dart/test/sentry_options_test.dart index f6dec29e90..e921c87b32 100644 --- a/dart/test/sentry_options_test.dart +++ b/dart/test/sentry_options_test.dart @@ -127,4 +127,10 @@ void main() { expect(options.isTracingEnabled(), false); }); + + test('Spotlight is disabled by default', () { + final options = SentryOptions(dsn: fakeDsn); + + expect(options.spotlight.enabled, false); + }); } From a8531c06b64958e81379c2c5436c445c4395cb63 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 22 Dec 2023 11:45:20 +0100 Subject: [PATCH 16/18] add format --- dart/test/sentry_client_test.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index ef2e1b1ac8..63c83a321f 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -1708,7 +1708,8 @@ void main() { expect(capturedEnvelope.header.dsn, fixture.options.dsn); }); - test('Spotlight enabled should set transport to SpotlightHttpTransport', () async { + test('Spotlight enabled should set transport to SpotlightHttpTransport', + () async { fixture.options.spotlight = Spotlight(enabled: true); fixture.getSut(); From fcd3e62e579b3cc0335ede5c1378dd9854ea80b9 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 22 Dec 2023 13:11:17 +0100 Subject: [PATCH 17/18] Fix CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4c2c7fd33..f9be82aea9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Features +- Add [Spotlight](https://spotlightjs.com/about/) support ([#1786](https://github.com/getsentry/sentry-dart/pull/1786)) - Add `ConnectivityIntegration` for web ([#1765](https://github.com/getsentry/sentry-dart/pull/1765)) - We only get the info if online/offline on web platform. The added breadcrumb is set to either `wifi` or `none`. - APM for isar ([#1726](https://github.com/getsentry/sentry-dart/pull/1726)) @@ -19,7 +20,6 @@ ### Features -- Add [Spotlight](https://spotlightjs.com/about/) support ([#1786](https://github.com/getsentry/sentry-dart/pull/1786)) - Add option to opt out of fatal level for automatically collected errors ([#1738](https://github.com/getsentry/sentry-dart/pull/1738)) - Add `Hive` breadcrumbs ([#1773](https://github.com/getsentry/sentry-dart/pull/1773)) From 573ae08ed8d3a7caf7e87f3bc0584948d49bf932 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 22 Dec 2023 13:13:04 +0100 Subject: [PATCH 18/18] Fix CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9be82aea9..71483dab8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features - Add [Spotlight](https://spotlightjs.com/about/) support ([#1786](https://github.com/getsentry/sentry-dart/pull/1786)) + - Set `options.spotlight = Spotlight(enabled: true)` to enable Spotlight - Add `ConnectivityIntegration` for web ([#1765](https://github.com/getsentry/sentry-dart/pull/1765)) - We only get the info if online/offline on web platform. The added breadcrumb is set to either `wifi` or `none`. - APM for isar ([#1726](https://github.com/getsentry/sentry-dart/pull/1726))