Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- Span ids not re-generating for headers created from scope ([#3051](https://github.com/getsentry/sentry-dart/pull/3051))
- `ScreenshotIntegration` not being added for web ([#3055](https://github.com/getsentry/sentry-dart/pull/3055))

### Enhancements
Expand Down
2 changes: 0 additions & 2 deletions dart/lib/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ export 'src/type_check_hint.dart';
// ignore: invalid_export_of_internal_element
export 'src/utils.dart';
// ignore: invalid_export_of_internal_element
export 'src/utils/add_tracing_headers_to_http_request.dart';
// ignore: invalid_export_of_internal_element
export 'src/utils/http_header_utils.dart';
// ignore: invalid_export_of_internal_element
export 'src/utils/http_sanitizer.dart';
Expand Down
1 change: 0 additions & 1 deletion dart/lib/src/http_client/tracing_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import '../hub_adapter.dart';
import '../protocol.dart';
import '../sentry_trace_origins.dart';
import '../tracing.dart';
import '../utils/add_tracing_headers_to_http_request.dart';
import '../utils/http_sanitizer.dart';
import '../utils/tracing_utils.dart';

Expand Down
10 changes: 3 additions & 7 deletions dart/lib/src/propagation_context.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import 'package:meta/meta.dart';

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

@internal
class PropagationContext {
/// Either represents the incoming `traceId` or the `traceId` generated by the current SDK, if there was no incoming trace.
SentryId traceId = SentryId.newId();

/// A span ID that should be used for the `trace` context of various event type, when performance is disabled or when there is no active span.
/// If this value is undefined on the propagation context, the SDK will generate a random span ID for `trace` contexts and trace propagation.
final SpanId spanId = SpanId.newId();

/// The dynamic sampling context.
SentryBaggage? baggage;

Expand All @@ -20,5 +15,6 @@ class PropagationContext {
baggage != null ? SentryBaggageHeader.fromBaggage(baggage!) : null;

/// Sentry trace header to attach to http headers.
SentryTraceHeader toSentryTrace() => SentryTraceHeader(traceId, spanId);
SentryTraceHeader toSentryTrace() =>
generateSentryTraceHeader(traceId: traceId);
}
6 changes: 3 additions & 3 deletions dart/lib/src/protocol/sentry_span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ class SentrySpan extends ISentrySpan {
Map<String, dynamic> get data => _data;

@override
SentryTraceHeader toSentryTrace() => SentryTraceHeader(
_context.traceId,
_context.spanId,
SentryTraceHeader toSentryTrace() => generateSentryTraceHeader(
traceId: _context.traceId,
spanId: _context.spanId,
sampled: samplingDecision?.sampled,
);

Expand Down
2 changes: 1 addition & 1 deletion dart/lib/src/protocol/sentry_trace_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class SentryTraceContext {
PropagationContext propagationContext) {
return SentryTraceContext(
traceId: propagationContext.traceId,
spanId: propagationContext.spanId,
spanId: SpanId.newId(),
operation: 'default',
replayId: propagationContext.baggage?.getReplayId());
}
Expand Down
27 changes: 0 additions & 27 deletions dart/lib/src/utils/add_tracing_headers_to_http_request.dart

This file was deleted.

39 changes: 39 additions & 0 deletions dart/lib/src/utils/tracing_utils.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
import '../../sentry.dart';

SentryTraceHeader generateSentryTraceHeader(
{SentryId? traceId, SpanId? spanId, bool? sampled}) {
traceId ??= SentryId.newId();
spanId ??= SpanId.newId();
return SentryTraceHeader(traceId, spanId, sampled: sampled);
}

void addTracingHeadersToHttpHeader(Map<String, dynamic> headers, Hub hub,
{ISentrySpan? span}) {
if (span != null) {
addSentryTraceHeaderFromSpan(span, headers);
addBaggageHeaderFromSpan(
span,
headers,
log: hub.options.log,
);
} else {
addSentryTraceHeaderFromScope(hub.scope, headers);
addBaggageHeaderFromScope(hub.scope, headers, log: hub.options.log);
}
}

void addSentryTraceHeaderFromScope(Scope scope, Map<String, dynamic> headers) {
final propagationContext = scope.propagationContext;
final traceHeader = propagationContext.toSentryTrace();
headers[traceHeader.name] = traceHeader.value;
}

void addSentryTraceHeaderFromSpan(
ISentrySpan span, Map<String, dynamic> headers) {
final traceHeader = span.toSentryTrace();
Expand All @@ -11,6 +39,17 @@ void addSentryTraceHeader(
headers[traceHeader.name] = traceHeader.value;
}

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

void addBaggageHeaderFromSpan(
ISentrySpan span,
Map<String, dynamic> headers, {
Expand Down
31 changes: 28 additions & 3 deletions dart/test/http_client/tracing_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,38 @@ void main() {
final response = await sut.get(requestUri);

final baggageHeader = propagationContext.toBaggageHeader();
final sentryTraceHeader = propagationContext.toSentryTrace();

expect(propagationContext.toBaggageHeader(), isNotNull);
expect(
response.request!.headers[baggageHeader!.name], baggageHeader.value);
expect(response.request!.headers[sentryTraceHeader.name],
sentryTraceHeader.value);

final traceHeader = SentryTraceHeader.fromTraceHeader(
response.request!.headers['sentry-trace'] as String,
);
expect(traceHeader.traceId, propagationContext.traceId);
// can't check span id as it is always generated new
});

test(
'tracing header from propagation context should generate new span ids for new events',
() async {
fixture._hub.options.tracesSampleRate = null;
fixture._hub.options.tracesSampler = null;
final sut = fixture.getSut(
client: fixture.getClient(statusCode: 200, reason: 'OK'),
);
final propagationContext = fixture._hub.scope.propagationContext;
propagationContext.baggage = SentryBaggage({'foo': 'bar'});

final response1 = await sut.get(requestUri);
final response2 = await sut.get(requestUri);

final traceHeader1 = SentryTraceHeader.fromTraceHeader(
response1.request!.headers['sentry-trace']!);
final traceHeader2 = SentryTraceHeader.fromTraceHeader(
response2.request!.headers['sentry-trace']!);

expect(traceHeader1.spanId, isNot(traceHeader2.spanId));
});

test(
Expand Down
25 changes: 23 additions & 2 deletions dart/test/scope_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -463,13 +463,34 @@ void main() {
true);
});

test('apply trace context to event', () async {
test('apply trace context to event with active span', () async {
final event = SentryEvent();
final scope = Scope(defaultTestOptions())..span = fixture.sentryTracer;

final updatedEvent = await scope.applyToEvent(event, Hint());

expect(updatedEvent?.contexts['trace'] is SentryTraceContext, true);
expect(updatedEvent?.contexts['trace'] is SentryTraceContext, isTrue);
});

test('apply trace context to event with propagation context', () async {
final event = SentryEvent();
final event2 = SentryEvent();
final scope = Scope(defaultTestOptions());

final updatedEvent = await scope.applyToEvent(event, Hint());

final traceContext =
updatedEvent?.contexts['trace'] as SentryTraceContext;
final spanId1 = traceContext.spanId;
expect(traceContext.traceId, scope.propagationContext.traceId);

final updatedEvent2 = await scope.applyToEvent(event2, Hint());
final traceContext2 =
updatedEvent2?.contexts['trace'] as SentryTraceContext;
final spanId2 = traceContext2.spanId;

// trace contexts from the scope should always re-generate span ids
expect(spanId1, isNot(spanId2));
});

test('should not apply the scope properties when event already has it ',
Expand Down
5 changes: 1 addition & 4 deletions dart/test/sentry_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -647,8 +647,7 @@ void main() {
expect(fixture.transport.envelopes.length, 1);
expect(
scopePropagationContext.traceId, sentryEvent.contexts.trace!.traceId);
expect(
scopePropagationContext.spanId, sentryEvent.contexts.trace!.spanId);
// not checking for span id as it should be a new generated random span id
});

test('keeps existing trace context if already present', () async {
Expand Down Expand Up @@ -680,8 +679,6 @@ void main() {
expect(spanContext.spanId, isNot(sentryEvent.contexts.trace!.spanId));
expect(propagationContext.traceId,
isNot(sentryEvent.contexts.trace!.traceId));
expect(
propagationContext.spanId, isNot(sentryEvent.contexts.trace!.spanId));
});

test(
Expand Down
15 changes: 15 additions & 0 deletions dart/test/sentry_trace_context_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:sentry/sentry.dart';
import 'package:sentry/src/propagation_context.dart';
import 'package:test/test.dart';

import 'mocks.dart';
Expand Down Expand Up @@ -48,6 +49,20 @@ void main() {
traceContext.replayId.toString(), '00000000000000000000000000000004');
expect(traceContext.data, {'key': 'value'});
});

test('fromPropagationContext creates valid SentryTraceContext', () {
final propagationContext = PropagationContext();

final traceContext1 =
SentryTraceContext.fromPropagationContext(propagationContext);
final traceContext2 =
SentryTraceContext.fromPropagationContext(propagationContext);

expect(traceContext1.traceId, propagationContext.traceId);
expect(traceContext1.traceId, traceContext1.traceId);
// the span id is always generated new when creating a trace context from scope
expect(traceContext1.spanId, isNot(traceContext2.spanId));
});
}

class Fixture {
Expand Down
Loading
Loading