Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions packages/dart/lib/src/http_client/tracing_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import '../hub.dart';
import '../hub_adapter.dart';
import '../protocol.dart';
import '../sentry_trace_origins.dart';
import '../tracing.dart';
import '../tracing/instrumentation/instrumentation.dart';
import '../utils/http_sanitizer.dart';
import '../utils/tracing_utils.dart';

Expand All @@ -19,13 +19,15 @@ class TracingClient extends BaseClient {
TracingClient({Client? client, Hub? hub})
: _hub = hub ?? HubAdapter(),
_client = client ?? Client() {
_spanFactory = _hub.options.spanFactory;
if (_hub.options.isTracingEnabled()) {
_hub.options.sdk.addIntegration(integrationName);
}
}

final Client _client;
final Hub _hub;
late final InstrumentationSpanFactory _spanFactory;

@override
Future<StreamedResponse> send(BaseRequest request) async {
Expand All @@ -37,40 +39,44 @@ class TracingClient extends BaseClient {
description += ' ${urlDetails.urlOrFallback}';
}

final currentSpan = _hub.getSpan();
var span = currentSpan?.startChild(
final parentSpan = _spanFactory.getSpan(_hub);
final instrumentationSpan = _spanFactory.createSpan(
parentSpan,
'http.client',
description: description,
);

if (span is NoOpSentrySpan) {
span = null;
}

// Regardless whether tracing is enabled or not, we always want to attach
// Sentry trace headers (tracing without performance).
if (containsTargetOrMatchesRegExp(
_hub.options.tracePropagationTargets, request.url.toString())) {
addTracingHeadersToHttpHeader(request.headers, _hub, span: span);
addTracingHeadersToHttpHeader(
request.headers,
_hub,
span: instrumentationSpan,
);
}

span?.origin = SentryTraceOrigins.autoHttpHttp;
span?.setData('http.request.method', request.method);
urlDetails?.applyToSpan(span);
instrumentationSpan?.origin = SentryTraceOrigins.autoHttpHttp;
instrumentationSpan?.setData('http.request.method', request.method);
urlDetails?.applyToSpan(instrumentationSpan);

StreamedResponse? response;
try {
response = await _client.send(request);
span?.setData('http.response.status_code', response.statusCode);
span?.setData('http.response_content_length', response.contentLength);
span?.status = SpanStatus.fromHttpStatusCode(response.statusCode);
instrumentationSpan?.setData(
'http.response.status_code', response.statusCode);
instrumentationSpan?.setData(
'http.response_content_length', response.contentLength);
instrumentationSpan?.status =
SpanStatus.fromHttpStatusCode(response.statusCode);
} catch (exception) {
span?.throwable = exception;
span?.status = SpanStatus.internalError();
instrumentationSpan?.throwable = exception;
instrumentationSpan?.status = SpanStatus.internalError();

rethrow;
} finally {
await span?.finish();
await instrumentationSpan?.finish();
}
return response;
}
Expand Down
52 changes: 18 additions & 34 deletions packages/dart/lib/src/sentry_baggage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:meta/meta.dart';
import 'protocol.dart';
import 'scope.dart';
import 'sentry_options.dart';
import 'utils/internal_logger.dart';

class SentryBaggage {
static const String _sampleRateKeyName = 'sentry-sample_rate';
Expand All @@ -11,13 +12,9 @@ class SentryBaggage {
static const int _maxChars = 8192;
static const int _maxListMember = 64;

SentryBaggage(
this._keyValues, {
this.log,
});
SentryBaggage(this._keyValues);

final Map<String, String> _keyValues;
final SdkLogCallback? log;

String toHeaderString() {
final buffer = StringBuffer();
Expand All @@ -26,9 +23,8 @@ class SentryBaggage {

for (final entry in _keyValues.entries) {
if (listMemberCount >= _maxListMember) {
log?.call(
SentryLevel.info,
'Baggage key ${entry.key} dropped because of max list member.',
internalLogger.info(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, using static internal logger, ignore my other comment.

() => 'Baggage key ${entry.key} dropped because of max list member.',
);
break;
}
Expand All @@ -40,9 +36,9 @@ class SentryBaggage {
final totalLengthIfValueAdded = buffer.length + encodedKeyValue.length;

if (totalLengthIfValueAdded >= _maxChars) {
log?.call(
SentryLevel.info,
'Baggage key ${entry.key} dropped because of max baggage chars.',
internalLogger.info(
() =>
'Baggage key ${entry.key} dropped because of max baggage chars.',
);
continue;
}
Expand All @@ -51,10 +47,9 @@ class SentryBaggage {
buffer.write(encodedKeyValue);
separator = ',';
} catch (exception, stackTrace) {
log?.call(
SentryLevel.error,
'Failed to parse the baggage key ${entry.key}.',
exception: exception,
internalLogger.error(
() => 'Failed to parse the baggage key ${entry.key}.',
error: exception,
stackTrace: stackTrace,
);
// TODO rethrow in options.automatedTestMode (currently not available here to check)
Expand All @@ -64,33 +59,25 @@ class SentryBaggage {
return buffer.toString();
}

factory SentryBaggage.fromHeaderList(
List<String> headerValues, {
SdkLogCallback? log,
}) {
factory SentryBaggage.fromHeaderList(List<String> headerValues) {
final keyValues = <String, String>{};

for (final headerValue in headerValues) {
final keyValuesToAdd = _extractKeyValuesFromBaggageString(
headerValue,
log: log,
);
keyValues.addAll(keyValuesToAdd);
}

return SentryBaggage(keyValues, log: log);
return SentryBaggage(keyValues);
}

factory SentryBaggage.fromHeader(
String headerValue, {
SdkLogCallback? log,
}) {
factory SentryBaggage.fromHeader(String headerValue) {
final keyValues = _extractKeyValuesFromBaggageString(
headerValue,
log: log,
);

return SentryBaggage(keyValues, log: log);
return SentryBaggage(keyValues);
}

@internal
Expand All @@ -113,9 +100,7 @@ class SentryBaggage {
}

static Map<String, String> _extractKeyValuesFromBaggageString(
String headerValue, {
SdkLogCallback? log,
}) {
String headerValue) {
final keyValues = <String, String>{};

final keyValueStrings = headerValue.split(',');
Expand All @@ -130,10 +115,9 @@ class SentryBaggage {
final value = _urlDecode(keyAndValue.last.trim());
keyValues[key] = value;
} catch (exception, stackTrace) {
log?.call(
SentryLevel.error,
'Failed to parse the baggage entry $keyAndValue.',
exception: exception,
internalLogger.error(
() => 'Failed to parse the baggage entry $keyAndValue.',
error: exception,
stackTrace: stackTrace,
);
}
Expand Down
5 changes: 2 additions & 3 deletions packages/dart/lib/src/sentry_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,8 @@ class SentryClient {
var traceContext = scope?.span?.traceContext();
if (traceContext == null) {
if (scope != null) {
scope.propagationContext.baggage ??=
SentryBaggage({}, log: _options.log)
..setValuesFromScope(scope, _options);
scope.propagationContext.baggage ??= SentryBaggage({})
..setValuesFromScope(scope, _options);
traceContext = SentryTraceContextHeader.fromBaggage(
scope.propagationContext.baggage!);
}
Expand Down
7 changes: 2 additions & 5 deletions packages/dart/lib/src/sentry_trace_context_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'package:meta/meta.dart';
import 'protocol/access_aware_map.dart';
import 'protocol/sentry_id.dart';
import 'sentry_baggage.dart';
import 'sentry_options.dart';

class SentryTraceContextHeader {
SentryTraceContextHeader(
Expand Down Expand Up @@ -70,10 +69,8 @@ class SentryTraceContextHeader {
};
}

SentryBaggage toBaggage({
SdkLogCallback? log,
}) {
final baggage = SentryBaggage({}, log: log);
SentryBaggage toBaggage() {
final baggage = SentryBaggage({});
Comment thread
cursor[bot] marked this conversation as resolved.
baggage.setTraceId(traceId.toString());
baggage.setPublicKey(publicKey);

Expand Down
2 changes: 1 addition & 1 deletion packages/dart/lib/src/sentry_tracer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ class SentryTracer extends ISentrySpan {
final context = traceContext();

if (context != null) {
final baggage = context.toBaggage(log: _hub.options.log);
final baggage = context.toBaggage();
return SentryBaggageHeader.fromBaggage(baggage);
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ abstract class InstrumentationSpan {
String? get origin;
set origin(String? origin);
Future<void> finish({SpanStatus? status, DateTime? endTimestamp});
SentryTraceHeader toSentryTrace();
SentryBaggageHeader? toBaggageHeader();
}

/// [InstrumentationSpan] implementation wrapping [ISentrySpan].
Expand Down Expand Up @@ -57,4 +59,10 @@ class LegacyInstrumentationSpan implements InstrumentationSpan {
DateTime? endTimestamp,
}) =>
_span.finish(status: status, endTimestamp: endTimestamp);

@override
SentryTraceHeader toSentryTrace() => _span.toSentryTrace();

@override
SentryBaggageHeader? toBaggageHeader() => _span.toBaggageHeader();
}
39 changes: 15 additions & 24 deletions packages/dart/lib/src/utils/tracing_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ SentryTraceHeader generateSentryTraceHeader(
return SentryTraceHeader(traceId, spanId, sampled: sampled);
}

void addTracingHeadersToHttpHeader(Map<String, dynamic> headers, Hub hub,
{ISentrySpan? span}) {
void addTracingHeadersToHttpHeader(
Map<String, dynamic> headers,
Hub hub, {
InstrumentationSpan? span,
}) {
if (span != null) {
if (hub.options.propagateTraceparent) {
addW3CHeaderFromSpan(span, headers);
Expand All @@ -17,14 +20,13 @@ void addTracingHeadersToHttpHeader(Map<String, dynamic> headers, Hub hub,
addBaggageHeaderFromSpan(
span,
headers,
log: hub.options.log,
);
} else {
if (hub.options.propagateTraceparent) {
addW3CHeaderFromScope(hub.scope, headers);
}
addSentryTraceHeaderFromScope(hub.scope, headers);
addBaggageHeaderFromScope(hub.scope, headers, log: hub.options.log);
addBaggageHeaderFromScope(hub.scope, headers);
}
}

Expand All @@ -35,7 +37,7 @@ void addSentryTraceHeaderFromScope(Scope scope, Map<String, dynamic> headers) {
}

void addSentryTraceHeaderFromSpan(
ISentrySpan span, Map<String, dynamic> headers) {
InstrumentationSpan span, Map<String, dynamic> headers) {
final traceHeader = span.toSentryTrace();
headers[traceHeader.name] = traceHeader.value;
}
Expand All @@ -45,7 +47,8 @@ void addSentryTraceHeader(
headers[traceHeader.name] = traceHeader.value;
}

void addW3CHeaderFromSpan(ISentrySpan span, Map<String, dynamic> headers) {
void addW3CHeaderFromSpan(
InstrumentationSpan span, Map<String, dynamic> headers) {
final traceHeader = span.toSentryTrace();
_addW3CHeaderFromSentryTrace(traceHeader, headers);
}
Expand All @@ -67,42 +70,30 @@ String formatAsW3CHeader(SentryTraceHeader traceHeader) {
return '00-${traceHeader.traceId}-${traceHeader.spanId}-$sampledBit';
}

void addBaggageHeaderFromScope(
Scope scope,
Map<String, dynamic> headers, {
SdkLogCallback? log,
}) {
void addBaggageHeaderFromScope(Scope scope, Map<String, dynamic> headers) {
final baggageHeader = scope.propagationContext.toBaggageHeader();
if (baggageHeader != null) {
addBaggageHeader(baggageHeader, headers, log: log);
addBaggageHeader(baggageHeader, headers);
}
}

void addBaggageHeaderFromSpan(
ISentrySpan span,
Map<String, dynamic> headers, {
SdkLogCallback? log,
}) {
InstrumentationSpan span, Map<String, dynamic> headers) {
final baggage = span.toBaggageHeader();
if (baggage != null) {
addBaggageHeader(baggage, headers, log: log);
addBaggageHeader(baggage, headers);
}
}

void addBaggageHeader(
SentryBaggageHeader baggage,
Map<String, dynamic> headers, {
SdkLogCallback? log,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need tha passed log anymore? What was it used for, are we now missing log infos?

}) {
SentryBaggageHeader baggage, Map<String, dynamic> headers) {
final currentValue = headers[baggage.name] as String? ?? '';

final currentBaggage = SentryBaggage.fromHeader(
currentValue,
log: log,
);
final sentryBaggage = SentryBaggage.fromHeader(
baggage.value,
log: log,
);

// overwrite sentry's keys https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#baggage
Expand All @@ -114,7 +105,7 @@ void addBaggageHeader(
...sentryBaggage.keyValues,
};

final newBaggage = SentryBaggage(mergedBaggage, log: log);
final newBaggage = SentryBaggage(mergedBaggage);

headers[baggage.name] = newBaggage.toHeaderString();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/lib/src/utils/url_details.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class UrlDetails {
late final urlOrFallback =
Uri.tryParse(url ?? _unknown)?.toString() ?? _unknown;

void applyToSpan(ISentrySpan? span) {
void applyToSpan(InstrumentationSpan? span) {
if (span == null) {
return;
}
Expand Down
8 changes: 8 additions & 0 deletions packages/dart/test/mocks/mock_span.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:mockito/mockito.dart';
import 'package:sentry/sentry.dart';

class MockSpan extends Mock implements SentrySpan {
final SentrySpanContext _context = SentrySpanContext(operation: 'test');
@override
SentrySpanContext get context => _context;
}
Loading
Loading