Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
buenaflor committed Dec 15, 2023
1 parent 3a985bd commit 52e500e
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 99 deletions.
2 changes: 1 addition & 1 deletion dart/lib/src/sentry_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
88 changes: 5 additions & 83 deletions dart/lib/src/transport/http_transport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -24,9 +24,7 @@ class HttpTransport implements Transport {

final ClientReportRecorder _recorder;

late _CredentialBuilder _credentialBuilder;

final Map<String, String> _headers;
late HttpTransportRequestCreator _httpTransportRequestCreator;

factory HttpTransport(SentryOptions options, RateLimiter rateLimiter) {
if (options.httpClient is NoOpClient) {
Expand All @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -95,27 +86,6 @@ class HttpTransport implements Transport {
return SentryId.fromId(eventId);
}

Future<StreamedRequest> _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'];
Expand All @@ -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<String, String> configure(Map<String, String> headers) {
return headers
..addAll(
<String, String>{'X-Sentry-Auth': _authHeader},
);
}
}

Map<String, String> _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;
}
95 changes: 95 additions & 0 deletions dart/lib/src/transport/http_transport_request_creator.dart
Original file line number Diff line number Diff line change
@@ -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<String, String> _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<StreamedRequest> 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<String, String> _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<String, String> configure(Map<String, String> headers) {
return headers
..addAll(
<String, String>{'X-Sentry-Auth': _authHeader},
);
}
}
39 changes: 24 additions & 15 deletions dart/lib/src/transport/spotlight_http_transport.dart
Original file line number Diff line number Diff line change
@@ -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<String, String> _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<SentryId?> send(SentryEnvelope envelope) async {
Expand All @@ -19,16 +31,13 @@ class SpotlightHttpTransport extends Transport {
}

Future<void> _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)
Expand All @@ -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})',
);
}
}
Expand Down

0 comments on commit 52e500e

Please sign in to comment.