Skip to content

Commit 1e094d3

Browse files
denrasemarandaneto
andauthored
Send trace origin (#1534)
Co-authored-by: Manoel Aranda Neto <[email protected]>
1 parent 6a40d32 commit 1e094d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+667
-160
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Features
6+
7+
- Send trace origin ([#1534](https://github.com/getsentry/sentry-dart/pull/1534))
8+
9+
[Trace origin](https://develop.sentry.dev/sdk/performance/trace-origin/) indicates what created a trace or a span. Not all transactions and spans contain enough information to tell whether the user or what precisely in the SDK created it. Origin solves this problem. The SDK now sends origin for transactions and spans.
10+
311
## 7.8.0
412

513
### Enhancements

dart/lib/sentry.dart

+2
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,5 @@ export 'src/utils/http_sanitizer.dart';
4444
export 'src/utils/url_details.dart';
4545
// ignore: invalid_export_of_internal_element
4646
export 'src/utils/http_header_utils.dart';
47+
// ignore: invalid_export_of_internal_element
48+
export 'src/sentry_trace_origins.dart';

dart/lib/src/http_client/tracing_client.dart

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:http/http.dart';
22
import '../hub.dart';
33
import '../hub_adapter.dart';
44
import '../protocol.dart';
5+
import '../sentry_trace_origins.dart';
56
import '../tracing.dart';
67
import '../utils/tracing_utils.dart';
78
import '../utils/http_sanitizer.dart';
@@ -33,6 +34,7 @@ class TracingClient extends BaseClient {
3334
'http.client',
3435
description: description,
3536
);
37+
span?.origin = SentryTraceOrigins.autoHttpHttp;
3638

3739
// if the span is NoOp, we don't want to attach headers
3840
if (span is NoOpSentrySpan) {

dart/lib/src/hub.dart

+7
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ class Hub {
398398
name,
399399
operation,
400400
description: description,
401+
origin: SentryTraceOrigins.manual,
401402
),
402403
startTimestamp: startTimestamp,
403404
bindToScope: bindToScope,
@@ -442,6 +443,12 @@ class Hub {
442443
transactionContext.copyWith(samplingDecision: samplingDecision);
443444
}
444445

446+
if (transactionContext.origin == null) {
447+
transactionContext = transactionContext.copyWith(
448+
origin: SentryTraceOrigins.manual,
449+
);
450+
}
451+
445452
final tracer = SentryTracer(
446453
transactionContext,
447454
this,

dart/lib/src/noop_sentry_span.dart

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ class NoOpSentrySpan extends ISentrySpan {
5151
@override
5252
SentrySpanContext get context => _spanContext;
5353

54+
@override
55+
String? get origin => null;
56+
57+
@override
58+
set origin(String? origin) {}
59+
5460
@override
5561
SpanStatus? get status => null;
5662

dart/lib/src/protocol/sentry_span.dart

+12
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class SentrySpan extends ISentrySpan {
3636
}) {
3737
_startTimestamp = startTimestamp?.toUtc() ?? _hub.options.clock();
3838
_finishedCallback = finishedCallback;
39+
_origin = _context.origin;
3940
}
4041

4142
@override
@@ -145,6 +146,14 @@ class SentrySpan extends ISentrySpan {
145146
@override
146147
SentrySpanContext get context => _context;
147148

149+
String? _origin;
150+
151+
@override
152+
String? get origin => _origin;
153+
154+
@override
155+
set origin(String? origin) => _origin = origin;
156+
148157
Map<String, dynamic> toJson() {
149158
final json = _context.toJson();
150159
json['start_timestamp'] =
@@ -162,6 +171,9 @@ class SentrySpan extends ISentrySpan {
162171
if (_tags.isNotEmpty) {
163172
json['tags'] = _tags;
164173
}
174+
if (_origin != null) {
175+
json['origin'] = _origin;
176+
}
165177
return json;
166178
}
167179

dart/lib/src/protocol/sentry_trace_context.dart

+11
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ class SentryTraceContext {
2828
/// The Span status
2929
final SpanStatus? status;
3030

31+
/// The origin of the span indicates what created the span.
32+
///
33+
/// @note Gets set by the SDK. It is not expected to be set manually by users.
34+
///
35+
/// @see <https://develop.sentry.dev/sdk/performance/trace-origin>
36+
final String? origin;
37+
3138
factory SentryTraceContext.fromJson(Map<String, dynamic> json) {
3239
return SentryTraceContext(
3340
operation: json['op'] as String,
@@ -41,6 +48,7 @@ class SentryTraceContext {
4148
? null
4249
: SpanStatus.fromString(json['status'] as String),
4350
sampled: true,
51+
origin: json['origin'] == null ? null : json['origin'] as String?,
4452
);
4553
}
4654

@@ -53,6 +61,7 @@ class SentryTraceContext {
5361
if (parentSpanId != null) 'parent_span_id': parentSpanId!.toString(),
5462
if (description != null) 'description': description,
5563
if (status != null) 'status': status!.toString(),
64+
if (origin != null) 'origin': origin,
5665
};
5766
}
5867

@@ -64,6 +73,7 @@ class SentryTraceContext {
6473
status: status,
6574
parentSpanId: parentSpanId,
6675
sampled: sampled,
76+
origin: origin,
6777
);
6878

6979
SentryTraceContext({
@@ -74,6 +84,7 @@ class SentryTraceContext {
7484
required this.operation,
7585
this.description,
7686
this.status,
87+
this.origin,
7788
}) : traceId = traceId ?? SentryId.newId(),
7889
spanId = spanId ?? SpanId.newId();
7990
}

dart/lib/src/sentry_span_context.dart

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ class SentrySpanContext {
2020
/// consistent across instances of the span.
2121
final String? description;
2222

23+
/// The origin of the span indicates what created the span.
24+
///
25+
/// Gets set by the SDK. It is not expected to be set manually by users.
26+
///
27+
/// See https://develop.sentry.dev/sdk/performance/trace-origin
28+
final String? origin;
29+
2330
/// Item encoded as JSON
2431
Map<String, dynamic> toJson() {
2532
return {
@@ -28,6 +35,7 @@ class SentrySpanContext {
2835
'op': operation,
2936
if (parentSpanId != null) 'parent_span_id': parentSpanId.toString(),
3037
if (description != null) 'description': description,
38+
if (origin != null) 'origin': origin,
3139
};
3240
}
3341

@@ -37,6 +45,7 @@ class SentrySpanContext {
3745
this.parentSpanId,
3846
required this.operation,
3947
this.description,
48+
this.origin,
4049
}) : traceId = traceId ?? SentryId.newId(),
4150
spanId = spanId ?? SpanId.newId();
4251

@@ -53,6 +62,7 @@ class SentrySpanContext {
5362
parentSpanId: parentSpanId,
5463
sampled: sampled,
5564
status: status,
65+
origin: origin,
5666
);
5767
}
5868
}

dart/lib/src/sentry_span_interface.dart

+10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ abstract class ISentrySpan {
3636
/// Gets the span context.
3737
SentrySpanContext get context;
3838

39+
/// Gets the span origin
40+
String? get origin;
41+
42+
/// Sets span origin.
43+
///
44+
/// Gets set by the SDK. It is not expected to be set manually by users.
45+
///
46+
/// See https://develop.sentry.dev/sdk/performance/trace-origin
47+
set origin(String? origin);
48+
3949
/// Returns the end timestamp if finished
4050
DateTime? get endTimestamp;
4151

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import 'package:meta/meta.dart';
2+
3+
@internal
4+
class SentryTraceOrigins {
5+
static const manual = 'manual';
6+
7+
static const autoNavigationRouteObserver = 'auto.navigation.route_observer';
8+
static const autoHttpHttp = 'auto.http.http';
9+
static const autoHttpDioHttpClientAdapter =
10+
'auto.http.dio.http_client_adapter';
11+
static const autoHttpDioTransformer = 'auto.http.dio.transformer';
12+
static const autoFile = 'auto.file';
13+
static const autoFileAssetBundle = 'auto.file.asset_bundle';
14+
static const autoDbSqfliteOpenDatabase = 'auto.db.sqflite.open_database';
15+
static const autoDbSqfliteBatch = 'auto.db.sqflite.batch';
16+
static const autoDbSqfliteDatabase = 'auto.db.sqflite.database';
17+
static const autoDbSqfliteDatabaseExecutor =
18+
'auto.db.sqflite.database_executor';
19+
static const autoDbSqfliteDatabaseFactory =
20+
'auto.db.sqflite.database_factory';
21+
}

dart/lib/src/sentry_tracer.dart

+6
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,12 @@ class SentryTracer extends ISentrySpan {
255255
@override
256256
SentrySpanContext get context => _rootSpan.context;
257257

258+
@override
259+
String? get origin => _rootSpan.origin;
260+
261+
@override
262+
set origin(String? origin) => _rootSpan.origin = origin;
263+
258264
@override
259265
DateTime get startTimestamp => _rootSpan.startTimestamp;
260266

dart/lib/src/sentry_transaction_context.dart

+6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:meta/meta.dart';
2+
import 'sentry_trace_origins.dart';
23

34
import 'protocol.dart';
45
import 'sentry_baggage.dart';
@@ -21,12 +22,14 @@ class SentryTransactionContext extends SentrySpanContext {
2122
SpanId? parentSpanId,
2223
this.transactionNameSource,
2324
this.samplingDecision,
25+
String? origin,
2426
}) : super(
2527
operation: operation,
2628
description: description,
2729
traceId: traceId,
2830
spanId: spanId,
2931
parentSpanId: parentSpanId,
32+
origin: origin,
3033
);
3134

3235
factory SentryTransactionContext.fromSentryTrace(
@@ -50,6 +53,7 @@ class SentryTransactionContext extends SentrySpanContext {
5053
: null,
5154
transactionNameSource:
5255
transactionNameSource ?? SentryTransactionNameSource.custom,
56+
origin: SentryTraceOrigins.manual,
5357
);
5458
}
5559

@@ -63,6 +67,7 @@ class SentryTransactionContext extends SentrySpanContext {
6367
SpanId? parentSpanId,
6468
SentryTransactionNameSource? transactionNameSource,
6569
SentryTracesSamplingDecision? samplingDecision,
70+
String? origin,
6671
}) =>
6772
SentryTransactionContext(
6873
name ?? this.name,
@@ -76,5 +81,6 @@ class SentryTransactionContext extends SentrySpanContext {
7681
transactionNameSource:
7782
transactionNameSource ?? this.transactionNameSource,
7883
samplingDecision: samplingDecision ?? this.samplingDecision,
84+
origin: origin ?? this.origin,
7985
);
8086
}

dart/test/http_client/tracing_client_test.dart

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ void main() {
4444
expect(span.data['http.fragment'], 'baz');
4545
expect(span.data['http.response.status_code'], 200);
4646
expect(span.data['http.response_content_length'], 2);
47+
expect(span.origin, SentryTraceOrigins.autoHttpHttp);
4748
});
4849

4950
test('finish span if errored request', () async {

dart/test/hub_test.dart

+17
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ void main() {
176176
expect(tr.context.description, 'desc');
177177
expect(tr.startTimestamp.isAtSameMomentAs(startTime), true);
178178
expect((tr as SentryTracer).name, 'name');
179+
expect(tr.origin, SentryTraceOrigins.manual);
179180
});
180181

181182
test('start transaction binds span to the scope', () async {
@@ -265,6 +266,22 @@ void main() {
265266
expect(tr.samplingDecision?.sampled, false);
266267
});
267268

269+
test('start transaction with context sets trace origin fallback', () async {
270+
final hub = fixture.getSut();
271+
final tr = hub.startTransactionWithContext(
272+
SentryTransactionContext('name', 'op'),
273+
);
274+
expect(tr.origin, SentryTraceOrigins.manual);
275+
});
276+
277+
test('start transaction with context keeps origin', () async {
278+
final hub = fixture.getSut();
279+
final tr = hub.startTransactionWithContext(
280+
SentryTransactionContext('name', 'op', origin: 'auto.navigation.test'),
281+
);
282+
expect(tr.origin, 'auto.navigation.test');
283+
});
284+
268285
test('start transaction return NoOp if performance is disabled', () async {
269286
final hub = fixture.getSut(tracesSampleRate: null);
270287

dart/test/sentry_span_context_test.dart

+7-5
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ void main() {
1414
expect(map['op'], 'op');
1515
expect(map['parent_span_id'], isNotNull);
1616
expect(map['description'], 'desc');
17+
expect(map['origin'], 'manual');
1718
});
1819

19-
test('toTraceContext gets sampled and status', () {
20+
test('toTraceContext gets sampled, status, and origin', () {
2021
final sut = fixture.getSut();
2122
final aborted = SpanStatus.aborted();
2223
final traceContext = sut.toTraceContext(
@@ -31,15 +32,16 @@ void main() {
3132
expect(traceContext.parentSpanId, isNotNull);
3233
expect(traceContext.description, 'desc');
3334
expect(traceContext.status, aborted);
35+
expect(traceContext.origin, 'manual');
3436
});
3537
}
3638

3739
class Fixture {
3840
SentrySpanContext getSut() {
3941
return SentrySpanContext(
40-
operation: 'op',
41-
parentSpanId: SpanId.newId(),
42-
description: 'desc',
43-
);
42+
operation: 'op',
43+
parentSpanId: SpanId.newId(),
44+
description: 'desc',
45+
origin: 'manual');
4446
}
4547
}

0 commit comments

Comments
 (0)