Skip to content

Commit

Permalink
Tracing without performance (#1621)
Browse files Browse the repository at this point in the history
* implement propagationContext

* remove sampled and parentSpanId for now

* update changelog

* fix build error

* create new propagation context on startTransaction if tracing is disabled

* remove print

* propagate trace for http requests

* add tracing client test

* fix tests

* format

* fix compile

* tests

* fix analysis score

* fix analysis score

* fix compilation

* fix score

* fix score

* fix score

* fix score

* update tests
  • Loading branch information
buenaflor authored Sep 6, 2023
1 parent 1d47eb7 commit 280ab9f
Show file tree
Hide file tree
Showing 18 changed files with 361 additions and 59 deletions.
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 'hint.dart';

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 @@ class HubAdapter implements Hub {
String transaction,
) =>
Sentry.currentHub.setSpanContext(throwable, span, transaction);

@override
Scope get scope => Sentry.currentHub.scope;
}
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 'package:meta/meta.dart';
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 @@ class NoOpHub implements Hub {

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

@override
Scope get scope => Scope(_options);
}
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 @@ class SentryBaggage {
return SentryBaggage(keyValues, logger: logger);
}

@internal
setValuesFromScope(Scope scope, SentryOptions options) {
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!);
}
}

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

0 comments on commit 280ab9f

Please sign in to comment.