Skip to content

Commit 280ab9f

Browse files
authored
Tracing without performance (#1621)
* 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
1 parent 1d47eb7 commit 280ab9f

18 files changed

+361
-59
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Features
6+
7+
- Tracing without performance ([#1621](https://github.com/getsentry/sentry-dart/pull/1621))
8+
59
### Fixes
610

711
- Normalize data properties of `SentryUser` and `Breadcrumb` before sending over method channel ([#1591](https://github.com/getsentry/sentry-dart/pull/1591))

dart/lib/src/http_client/tracing_client.dart

+18-5
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,28 @@ class TracingClient extends BaseClient {
4646

4747
StreamedResponse? response;
4848
try {
49-
if (span != null) {
50-
if (containsTargetOrMatchesRegExp(
51-
_hub.options.tracePropagationTargets, request.url.toString())) {
52-
addSentryTraceHeader(span, request.headers);
53-
addBaggageHeader(
49+
if (containsTargetOrMatchesRegExp(
50+
_hub.options.tracePropagationTargets, request.url.toString())) {
51+
if (span != null) {
52+
addSentryTraceHeaderFromSpan(span, request.headers);
53+
addBaggageHeaderFromSpan(
5454
span,
5555
request.headers,
5656
logger: _hub.options.logger,
5757
);
58+
} else {
59+
final scope = _hub.scope;
60+
final propagationContext = scope.propagationContext;
61+
62+
final traceHeader = propagationContext.toSentryTrace();
63+
addSentryTraceHeader(traceHeader, request.headers);
64+
65+
final baggage = propagationContext.baggage;
66+
if (baggage != null) {
67+
final baggageHeader = SentryBaggageHeader.fromBaggage(baggage);
68+
addBaggageHeader(baggageHeader, request.headers,
69+
logger: _hub.options.logger);
70+
}
5871
}
5972
}
6073

dart/lib/src/hub.dart

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22
import 'dart:collection';
33

44
import 'package:meta/meta.dart';
5+
import 'propagation_context.dart';
56
import 'transport/data_category.dart';
67

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

69+
@internal
70+
Scope get scope => _peek().scope;
71+
6872
/// Captures the event.
6973
Future<SentryId> captureEvent(
7074
SentryEvent event, {
@@ -426,10 +430,8 @@ class Hub {
426430
"Instance is disabled and this 'startTransaction' call is a no-op.",
427431
);
428432
} else if (!_options.isTracingEnabled()) {
429-
_options.logger(
430-
SentryLevel.info,
431-
"Tracing is disabled and this 'startTransaction' returns a no-op.",
432-
);
433+
final item = _peek();
434+
item.scope.propagationContext = PropagationContext();
433435
} else {
434436
final item = _peek();
435437

dart/lib/src/hub_adapter.dart

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'hint.dart';
55

66
import 'hub.dart';
77
import 'protocol.dart';
8+
import 'scope.dart';
89
import 'sentry.dart';
910
import 'sentry_client.dart';
1011
import 'sentry_user_feedback.dart';
@@ -166,4 +167,7 @@ class HubAdapter implements Hub {
166167
String transaction,
167168
) =>
168169
Sentry.currentHub.setSpanContext(throwable, span, transaction);
170+
171+
@override
172+
Scope get scope => Sentry.currentHub.scope;
169173
}

dart/lib/src/noop_hub.dart

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:meta/meta.dart';
55
import 'hint.dart';
66
import 'hub.dart';
77
import 'protocol.dart';
8+
import 'scope.dart';
89
import 'sentry_client.dart';
910
import 'sentry_options.dart';
1011
import 'sentry_user_feedback.dart';
@@ -118,4 +119,7 @@ class NoOpHub implements Hub {
118119

119120
@override
120121
void setSpanContext(throwable, ISentrySpan span, String transaction) {}
122+
123+
@override
124+
Scope get scope => Scope(_options);
121125
}

dart/lib/src/propagation_context.dart

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import 'package:meta/meta.dart';
2+
import 'protocol.dart';
3+
import 'sentry_baggage.dart';
4+
5+
@internal
6+
class PropagationContext {
7+
late SentryId traceId = SentryId.newId();
8+
late SpanId spanId = SpanId.newId();
9+
SentryBaggage? baggage;
10+
11+
SentryTraceHeader toSentryTrace() => SentryTraceHeader(traceId, spanId);
12+
}

dart/lib/src/protocol/sentry_trace_context.dart

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import 'package:meta/meta.dart';
22

3+
import '../../sentry.dart';
4+
import '../propagation_context.dart';
35
import '../protocol.dart';
46

57
@immutable
@@ -87,4 +89,14 @@ class SentryTraceContext {
8789
this.origin,
8890
}) : traceId = traceId ?? SentryId.newId(),
8991
spanId = spanId ?? SpanId.newId();
92+
93+
@internal
94+
factory SentryTraceContext.fromPropagationContext(
95+
PropagationContext propagationContext) {
96+
return SentryTraceContext(
97+
traceId: propagationContext.traceId,
98+
spanId: propagationContext.spanId,
99+
operation: 'default',
100+
);
101+
}
90102
}

dart/lib/src/scope.dart

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import 'dart:async';
22
import 'dart:collection';
33

4+
import 'package:meta/meta.dart';
5+
46
import 'event_processor.dart';
57
import 'hint.dart';
8+
import 'propagation_context.dart';
69
import 'protocol.dart';
710
import 'scope_observer.dart';
811
import 'sentry_attachment/sentry_attachment.dart';
@@ -39,6 +42,9 @@ class Scope {
3942
/// Returns active transaction or null if there is no active transaction.
4043
ISentrySpan? span;
4144

45+
@internal
46+
PropagationContext propagationContext = PropagationContext();
47+
4248
SentryUser? _user;
4349

4450
/// Get the current user.
@@ -311,10 +317,15 @@ class Scope {
311317
});
312318

313319
final newSpan = span;
314-
if (event.contexts.trace == null && newSpan != null) {
315-
event.contexts.trace = newSpan.context.toTraceContext(
316-
sampled: newSpan.samplingDecision?.sampled,
317-
);
320+
if (event.contexts.trace == null) {
321+
if (newSpan != null) {
322+
event.contexts.trace = newSpan.context.toTraceContext(
323+
sampled: newSpan.samplingDecision?.sampled,
324+
);
325+
} else {
326+
event.contexts.trace =
327+
SentryTraceContext.fromPropagationContext(propagationContext);
328+
}
318329
}
319330

320331
SentryEvent? processedEvent = event;

dart/lib/src/sentry_baggage.dart

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import 'protocol/sentry_level.dart';
1+
import 'package:meta/meta.dart';
2+
import 'scope.dart';
3+
import 'protocol.dart';
4+
25
import 'sentry_options.dart';
36

47
class SentryBaggage {
@@ -87,6 +90,27 @@ class SentryBaggage {
8790
return SentryBaggage(keyValues, logger: logger);
8891
}
8992

93+
@internal
94+
setValuesFromScope(Scope scope, SentryOptions options) {
95+
final propagationContext = scope.propagationContext;
96+
setTraceId(propagationContext.traceId.toString());
97+
if (options.dsn != null) {
98+
setPublicKey(Dsn.parse(options.dsn!).publicKey);
99+
}
100+
if (options.release != null) {
101+
setRelease(options.release!);
102+
}
103+
if (options.environment != null) {
104+
setEnvironment(options.environment!);
105+
}
106+
if (scope.user?.id != null) {
107+
setUserId(scope.user!.id!);
108+
}
109+
if (scope.user?.segment != null) {
110+
setUserSegment(scope.user!.segment!);
111+
}
112+
}
113+
90114
static Map<String, String> _extractKeyValuesFromBaggageString(
91115
String headerValue, {
92116
SentryLogger? logger,

dart/lib/src/sentry_client.dart

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22
import 'dart:math';
33
import 'package:meta/meta.dart';
4+
import 'sentry_baggage.dart';
45
import 'sentry_attachment/sentry_attachment.dart';
56

67
import 'event_processor.dart';
@@ -122,11 +123,24 @@ class SentryClient {
122123
attachments.add(viewHierarchy);
123124
}
124125

126+
var traceContext = scope?.span?.traceContext();
127+
if (traceContext == null) {
128+
if (scope?.propagationContext.baggage == null) {
129+
scope?.propagationContext.baggage =
130+
SentryBaggage({}, logger: _options.logger);
131+
scope?.propagationContext.baggage?.setValuesFromScope(scope, _options);
132+
}
133+
if (scope != null) {
134+
traceContext = SentryTraceContextHeader.fromBaggage(
135+
scope.propagationContext.baggage!);
136+
}
137+
}
138+
125139
final envelope = SentryEnvelope.fromEvent(
126140
preparedEvent,
127141
_options.sdk,
128142
dsn: _options.dsn,
129-
traceContext: scope?.span?.traceContext(),
143+
traceContext: traceContext,
130144
attachments: attachments.isNotEmpty ? attachments : null,
131145
);
132146

dart/lib/src/sentry_trace_context_header.dart

+9
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,13 @@ class SentryTraceContextHeader {
7979

8080
return baggage;
8181
}
82+
83+
factory SentryTraceContextHeader.fromBaggage(SentryBaggage baggage) {
84+
return SentryTraceContextHeader(
85+
SentryId.fromId(baggage.get('sentry-trace_id').toString()),
86+
baggage.get('sentry-public_key').toString(),
87+
release: baggage.get('sentry-release'),
88+
environment: baggage.get('sentry-environment'),
89+
);
90+
}
8291
}

dart/lib/src/utils/tracing_utils.dart

+35-22
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,55 @@
11
import '../../sentry.dart';
22

3-
void addSentryTraceHeader(ISentrySpan span, Map<String, dynamic> headers) {
3+
void addSentryTraceHeaderFromSpan(
4+
ISentrySpan span, Map<String, dynamic> headers) {
45
final traceHeader = span.toSentryTrace();
56
headers[traceHeader.name] = traceHeader.value;
67
}
78

8-
void addBaggageHeader(
9+
void addSentryTraceHeader(
10+
SentryTraceHeader traceHeader, Map<String, dynamic> headers) {
11+
headers[traceHeader.name] = traceHeader.value;
12+
}
13+
14+
void addBaggageHeaderFromSpan(
915
ISentrySpan span,
1016
Map<String, dynamic> headers, {
1117
SentryLogger? logger,
1218
}) {
1319
final baggage = span.toBaggageHeader();
1420
if (baggage != null) {
15-
final currentValue = headers[baggage.name] as String? ?? '';
21+
addBaggageHeader(baggage, headers, logger: logger);
22+
}
23+
}
1624

17-
final currentBaggage = SentryBaggage.fromHeader(
18-
currentValue,
19-
logger: logger,
20-
);
21-
final sentryBaggage = SentryBaggage.fromHeader(
22-
baggage.value,
23-
logger: logger,
24-
);
25+
void addBaggageHeader(
26+
SentryBaggageHeader baggage,
27+
Map<String, dynamic> headers, {
28+
SentryLogger? logger,
29+
}) {
30+
final currentValue = headers[baggage.name] as String? ?? '';
2531

26-
// overwrite sentry's keys https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#baggage
27-
final filteredBaggageHeader = Map.from(currentBaggage.keyValues);
28-
filteredBaggageHeader
29-
.removeWhere((key, value) => key.startsWith('sentry-'));
32+
final currentBaggage = SentryBaggage.fromHeader(
33+
currentValue,
34+
logger: logger,
35+
);
36+
final sentryBaggage = SentryBaggage.fromHeader(
37+
baggage.value,
38+
logger: logger,
39+
);
3040

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

36-
final newBaggage = SentryBaggage(mergedBaggage, logger: logger);
45+
final mergedBaggage = <String, String>{
46+
...filteredBaggageHeader,
47+
...sentryBaggage.keyValues,
48+
};
3749

38-
headers[baggage.name] = newBaggage.toHeaderString();
39-
}
50+
final newBaggage = SentryBaggage(mergedBaggage, logger: logger);
51+
52+
headers[baggage.name] = newBaggage.toHeaderString();
4053
}
4154

4255
bool containsTargetOrMatchesRegExp(

0 commit comments

Comments
 (0)