Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracing without performance #1621

Merged
merged 23 commits into from
Sep 6, 2023
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Features

- Tracing without performance ([#1621](https://github.com/getsentry/sentry-dart/pull/1621))

### Fixes

- Normalize data properties of `SentryUser` and `Breadcrumb` before sending over method channel ([#1591](https://github.com/getsentry/sentry-dart/pull/1591))
Expand Down
23 changes: 18 additions & 5 deletions dart/lib/src/http_client/tracing_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,28 @@ class TracingClient extends BaseClient {

StreamedResponse? response;
try {
if (span != null) {
if (containsTargetOrMatchesRegExp(
_hub.options.tracePropagationTargets, request.url.toString())) {
addSentryTraceHeader(span, request.headers);
addBaggageHeader(
if (containsTargetOrMatchesRegExp(
_hub.options.tracePropagationTargets, request.url.toString())) {
if (span != null) {
addSentryTraceHeaderFromSpan(span, request.headers);
addBaggageHeaderFromSpan(
span,
request.headers,
logger: _hub.options.logger,
);
} else {
final scope = _hub.scope;
final propagationContext = scope.propagationContext;

final traceHeader = propagationContext.toSentryTrace();
addSentryTraceHeader(traceHeader, request.headers);

final baggage = propagationContext.baggage;
if (baggage != null) {
final baggageHeader = SentryBaggageHeader.fromBaggage(baggage);
addBaggageHeader(baggageHeader, request.headers,
logger: _hub.options.logger);
}
}
}

Expand Down
10 changes: 6 additions & 4 deletions dart/lib/src/hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:collection';

import 'package:meta/meta.dart';
import 'propagation_context.dart';
import 'transport/data_category.dart';

import '../sentry.dart';
Expand Down Expand Up @@ -65,6 +66,9 @@ class Hub {
/// Last event id recorded by the Hub
SentryId get lastEventId => _lastEventId;

@internal
Scope get scope => _peek().scope;

/// Captures the event.
Future<SentryId> captureEvent(
SentryEvent event, {
Expand Down Expand Up @@ -426,10 +430,8 @@ class Hub {
"Instance is disabled and this 'startTransaction' call is a no-op.",
);
} else if (!_options.isTracingEnabled()) {
_options.logger(
SentryLevel.info,
"Tracing is disabled and this 'startTransaction' returns a no-op.",
);
final item = _peek();
item.scope.propagationContext = PropagationContext();
} else {
final item = _peek();

Expand Down
4 changes: 4 additions & 0 deletions dart/lib/src/hub_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import 'hub.dart';
import 'protocol.dart';
import 'scope.dart';
import 'sentry.dart';
import 'sentry_client.dart';
import 'sentry_user_feedback.dart';
Expand Down Expand Up @@ -166,4 +167,7 @@
String transaction,
) =>
Sentry.currentHub.setSpanContext(throwable, span, transaction);

@override
Scope get scope => Sentry.currentHub.scope;

Check warning on line 172 in dart/lib/src/hub_adapter.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/hub_adapter.dart#L171-L172

Added lines #L171 - L172 were not covered by tests
}
4 changes: 4 additions & 0 deletions dart/lib/src/noop_hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'hint.dart';
import 'hub.dart';
import 'protocol.dart';
import 'scope.dart';
import 'sentry_client.dart';
import 'sentry_options.dart';
import 'sentry_user_feedback.dart';
Expand Down Expand Up @@ -118,4 +119,7 @@

@override
void setSpanContext(throwable, ISentrySpan span, String transaction) {}

@override
Scope get scope => Scope(_options);

Check warning on line 124 in dart/lib/src/noop_hub.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/noop_hub.dart#L123-L124

Added lines #L123 - L124 were not covered by tests
}
12 changes: 12 additions & 0 deletions dart/lib/src/propagation_context.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:meta/meta.dart';
import 'protocol.dart';
import 'sentry_baggage.dart';

@internal
class PropagationContext {
late SentryId traceId = SentryId.newId();
late SpanId spanId = SpanId.newId();
SentryBaggage? baggage;

SentryTraceHeader toSentryTrace() => SentryTraceHeader(traceId, spanId);
}
12 changes: 12 additions & 0 deletions dart/lib/src/protocol/sentry_trace_context.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:meta/meta.dart';

import '../../sentry.dart';
import '../propagation_context.dart';
import '../protocol.dart';

@immutable
Expand Down Expand Up @@ -87,4 +89,14 @@ class SentryTraceContext {
this.origin,
}) : traceId = traceId ?? SentryId.newId(),
spanId = spanId ?? SpanId.newId();

@internal
factory SentryTraceContext.fromPropagationContext(
PropagationContext propagationContext) {
return SentryTraceContext(
traceId: propagationContext.traceId,
spanId: propagationContext.spanId,
operation: 'default',
);
}
}
19 changes: 15 additions & 4 deletions dart/lib/src/scope.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'dart:async';
import 'dart:collection';

import 'package:meta/meta.dart';

import 'event_processor.dart';
import 'hint.dart';
import 'propagation_context.dart';
import 'protocol.dart';
import 'scope_observer.dart';
import 'sentry_attachment/sentry_attachment.dart';
Expand Down Expand Up @@ -39,6 +42,9 @@ class Scope {
/// Returns active transaction or null if there is no active transaction.
ISentrySpan? span;

@internal
PropagationContext propagationContext = PropagationContext();

SentryUser? _user;

/// Get the current user.
Expand Down Expand Up @@ -311,10 +317,15 @@ class Scope {
});

final newSpan = span;
if (event.contexts.trace == null && newSpan != null) {
event.contexts.trace = newSpan.context.toTraceContext(
sampled: newSpan.samplingDecision?.sampled,
);
if (event.contexts.trace == null) {
if (newSpan != null) {
event.contexts.trace = newSpan.context.toTraceContext(
sampled: newSpan.samplingDecision?.sampled,
);
} else {
event.contexts.trace =
SentryTraceContext.fromPropagationContext(propagationContext);
}
}

SentryEvent? processedEvent = event;
Expand Down
26 changes: 25 additions & 1 deletion dart/lib/src/sentry_baggage.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'protocol/sentry_level.dart';
import 'package:meta/meta.dart';
import 'scope.dart';
import 'protocol.dart';

import 'sentry_options.dart';

class SentryBaggage {
Expand Down Expand Up @@ -87,6 +90,27 @@
return SentryBaggage(keyValues, logger: logger);
}

@internal
setValuesFromScope(Scope scope, SentryOptions options) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

On Java we are setting transaction and sampleRate to null. Is this also needed here?

final propagationContext = scope.propagationContext;
setTraceId(propagationContext.traceId.toString());
if (options.dsn != null) {
setPublicKey(Dsn.parse(options.dsn!).publicKey);
}
if (options.release != null) {
setRelease(options.release!);
}
if (options.environment != null) {
setEnvironment(options.environment!);
}
if (scope.user?.id != null) {
setUserId(scope.user!.id!);
}
if (scope.user?.segment != null) {
setUserSegment(scope.user!.segment!);

Check warning on line 110 in dart/lib/src/sentry_baggage.dart

View check run for this annotation

Codecov / codecov/patch

dart/lib/src/sentry_baggage.dart#L110

Added line #L110 was not covered by tests
}
}

static Map<String, String> _extractKeyValuesFromBaggageString(
String headerValue, {
SentryLogger? logger,
Expand Down
16 changes: 15 additions & 1 deletion dart/lib/src/sentry_client.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:math';
import 'package:meta/meta.dart';
import 'sentry_baggage.dart';
import 'sentry_attachment/sentry_attachment.dart';

import 'event_processor.dart';
Expand Down Expand Up @@ -122,11 +123,24 @@ class SentryClient {
attachments.add(viewHierarchy);
}

var traceContext = scope?.span?.traceContext();
if (traceContext == null) {
if (scope?.propagationContext.baggage == null) {
scope?.propagationContext.baggage =
SentryBaggage({}, logger: _options.logger);
scope?.propagationContext.baggage?.setValuesFromScope(scope, _options);
}
if (scope != null) {
traceContext = SentryTraceContextHeader.fromBaggage(
scope.propagationContext.baggage!);
}
}

final envelope = SentryEnvelope.fromEvent(
preparedEvent,
_options.sdk,
dsn: _options.dsn,
traceContext: scope?.span?.traceContext(),
traceContext: traceContext,
attachments: attachments.isNotEmpty ? attachments : null,
);

Expand Down
9 changes: 9 additions & 0 deletions dart/lib/src/sentry_trace_context_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,13 @@ class SentryTraceContextHeader {

return baggage;
}

factory SentryTraceContextHeader.fromBaggage(SentryBaggage baggage) {
return SentryTraceContextHeader(
SentryId.fromId(baggage.get('sentry-trace_id').toString()),
baggage.get('sentry-public_key').toString(),
release: baggage.get('sentry-release'),
environment: baggage.get('sentry-environment'),
);
}
}
57 changes: 35 additions & 22 deletions dart/lib/src/utils/tracing_utils.dart
Original file line number Diff line number Diff line change
@@ -1,42 +1,55 @@
import '../../sentry.dart';

void addSentryTraceHeader(ISentrySpan span, Map<String, dynamic> headers) {
void addSentryTraceHeaderFromSpan(
ISentrySpan span, Map<String, dynamic> headers) {
final traceHeader = span.toSentryTrace();
headers[traceHeader.name] = traceHeader.value;
}

void addBaggageHeader(
void addSentryTraceHeader(
SentryTraceHeader traceHeader, Map<String, dynamic> headers) {
headers[traceHeader.name] = traceHeader.value;
}

void addBaggageHeaderFromSpan(
ISentrySpan span,
Map<String, dynamic> headers, {
SentryLogger? logger,
}) {
final baggage = span.toBaggageHeader();
if (baggage != null) {
final currentValue = headers[baggage.name] as String? ?? '';
addBaggageHeader(baggage, headers, logger: logger);
}
}

final currentBaggage = SentryBaggage.fromHeader(
currentValue,
logger: logger,
);
final sentryBaggage = SentryBaggage.fromHeader(
baggage.value,
logger: logger,
);
void addBaggageHeader(
SentryBaggageHeader baggage,
Map<String, dynamic> headers, {
SentryLogger? logger,
}) {
final currentValue = headers[baggage.name] as String? ?? '';

// overwrite sentry's keys https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#baggage
final filteredBaggageHeader = Map.from(currentBaggage.keyValues);
filteredBaggageHeader
.removeWhere((key, value) => key.startsWith('sentry-'));
final currentBaggage = SentryBaggage.fromHeader(
currentValue,
logger: logger,
);
final sentryBaggage = SentryBaggage.fromHeader(
baggage.value,
logger: logger,
);

final mergedBaggage = <String, String>{
...filteredBaggageHeader,
...sentryBaggage.keyValues,
};
// overwrite sentry's keys https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#baggage
final filteredBaggageHeader = Map.from(currentBaggage.keyValues);
filteredBaggageHeader.removeWhere((key, value) => key.startsWith('sentry-'));

final newBaggage = SentryBaggage(mergedBaggage, logger: logger);
final mergedBaggage = <String, String>{
...filteredBaggageHeader,
...sentryBaggage.keyValues,
};

headers[baggage.name] = newBaggage.toHeaderString();
}
final newBaggage = SentryBaggage(mergedBaggage, logger: logger);

headers[baggage.name] = newBaggage.toHeaderString();
}

bool containsTargetOrMatchesRegExp(
Expand Down
Loading
Loading